/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package compilador;
import compilador.datos.*;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import util.Consola;
/**
 *
 * @author Iñaki Goffard, Javier S. Pardo
 */
public class Traductor {
    private static final String mensajesError[][] = {
        {"INCONTEXTUAL","Se esperaba una instrucción, pero se recibe : ?."},  //0
        {"INCONTEXTUAL","Se esperaba: identificador de tipo, pero se recibe: ?."},  //1
        {"INCONTEXTUAL","Se esperaba: ? , pero se recibe: ?."},  //2
        {"INCONTEXTUAL","Se esperaba: ? ,o bien se esperaba ';', pero se recibe: ?."},  //3
        {"INCONTEXTUAL","¡¡¡Programa incorrecto!!! Error en instrucción de entrada/salida."},  //4
        {"INCONTEXTUAL","¡¡¡Programa incorrecto!!! Error en bloque de instrucciones."},  //5
        {"CONTEXTUAL","La variable ? no ha sido declarada."}, //6
        {"CONTEXTUAL","Se esperaba una variable y no un tipo."}, //7
        {"CONTEXTUAL","El tipo del operando no es compatible con el operador '?'."},  //8
        {"CONTEXTUAL","Los tipos de los operandos no son compatibles con el operador '?'."},    //9
        {"CONTEXTUAL","Tipos incompatibles para la asignación."},    //10
        {"CONTEXTUAL","La variable ? ha sido declarada previamente en el mismo nivel."},    //11
        {"CONTEXTUAL","La variable ? es una palabra reservada del lenguaje."},    //12
        {"CONTEXTUAL","La condición debe ser una expresión booleana."},    //13
        {"CONTEXTUAL","La variable no es de tipo natural o entera."},    //14
        {"CONTEXTUAL","La expresión no es de tipo natural o entera."},    //15
        {"CONTEXTUAL","El tipo base del puntero no se ha definido."}, //16
        {"CONTEXTUAL","La variable ? tiene un tipo erroneo."}, //17
        {"CONTEXTUAL","No se permiten declarar procedimientos con cuerpo diferido: ?."} //18
    };

    private static final int ERR_SE_ESPERABA_INST = 0;
    private static final int ERR_SE_ESPERABA_TIPO = 1;
    private static final int ERR_TOKEN_NO_ESPERADO = 2;
    private static final int ERR_TOKEN_NO_ESPERADO_2 = 3;
    private static final int ERR_INST_E_S = 4;
    private static final int ERR_BLOQUE_INST = 5;
    private static final int ERR_VAR_NO_DECLARADA = 6;
    private static final int ERR_SE_ESPERABA_VAR = 7;
    private static final int ERR_INCOMP_OPERADOR_OPERANDO = 8;
    private static final int ERR_INCOMP_OPERANDOS = 9;
    private static final int ERR_INCOMP_TIPOS_ASIG = 10;
    private static final int ERR_VAR_YA_DECLARADA = 11;
    private static final int ERR_VAR_ES_PALRES = 12;
    private static final int ERR_COND_NO_ES_BOOL = 13;
    private static final int ERR_VAR_NO_INT_NAT = 14;
    private static final int ERR_EXP_NO_INT_NAT = 15;
    private static final int ERR_NO_TIPO_BASE_PUNT = 16;
    private static final int ERR_TIPO_ERRONEO = 17;
    private static final int ERR_PROC_CUERPO_DIFERIDO = 18;


    private final String NOM_FICH_TRAZAS_ASIN = "TrazasASin.log";
    private final String NOM_FICH_TABLA_SIMBOLOS = "TS.log";
    private final String CLASE_ID_VAR_PAR_VALOR = "var";
    private final String CLASE_ID_VAR_PAR_VBLE = "pvar";
    private final String CLASE_ID_TIPO = "tipo";
    private final String CLASE_ID_PROC = "proc";

    private Token actual;

    private AnalizadorLex lex;

    private boolean error;

    private String tipo;

//    private Hashtable tablaSimbolos;

    private TS tablaSimbolos;
//    private Archivo cod;

    //Nombre del fichero objeto que se genera
    private String sNomFichObjeto;

    //Buffer de almacenamiento temporal de las instrucciones de codigo generadas
    private BufferInstruc bufferInstr;  

    //Ventana que muestra en tiempo real informacion sobre todo lo que esta sucediendo.
    private Consola consolaDebug;
    
    //Fichero de trazas que contiene las reglas evaluadas por el Analizador Sintactico
    //en el orden de evaluación
    private Archivo archivoTrazas;
    //Fichero de trazas que almacena el contenido de la Tabla de Simbolos.
    private Archivo archivoTS;
    //Flag para indicar el funcionamiento en modo traza.
    private boolean bModoTraza;
    //Nivel de profundidad en el árbol sintáctico (para mostrar las trazas por niveles)
    private int iNivelProf = 0;

    //Solo se aborta si se detecta un error sintactico NO contextual.
    private boolean abortar;

    private boolean emiteCodigo;

    private GestorErrores gestErr;

// Ya no hace falta, el contador de instrucciones se lleva en bufferInstr
//    private int etq; //Etiqueta global para contar instrucciones 

    private Hashtable visitadas; //Lista de expresiones visitadas

    public Traductor (AnalizadorLex lex, String sNomFichObjeto,  boolean bModoTraza, GestorErrores gestErr){
        //Guardo el nombre del fichero objeto para mas adelante.
        this.sNomFichObjeto = sNomFichObjeto;
//        this.cod = new Archivo(sNomFichObjeto, Archivo.MODO_ESCRITURA);
        inicializar (lex, bModoTraza, gestErr);
    }

    private void inicializar(AnalizadorLex lex,  boolean bModoTraza, GestorErrores gestErr){
        this.lex = lex;
//        this.tablaSimbolos=new Hashtable();
        this.tablaSimbolos=new TS();
        this.abortar = false;
        this.emiteCodigo = true;
        this.gestErr = gestErr;
        this.bModoTraza = bModoTraza;
        this.visitadas = new Hashtable();
        this.bufferInstr = new BufferInstruc();
    }
            
    //Método que arranca todo el proceso
    public void parser (){
        Archivo ficheroObjeto = null;

        if (this.bModoTraza){
            this.archivoTrazas = new Archivo (NOM_FICH_TRAZAS_ASIN, Archivo.MODO_ESCRITURA);
            this.archivoTS = new Archivo (NOM_FICH_TABLA_SIMBOLOS, Archivo.MODO_ESCRITURA);
            this.tablaSimbolos.setFichTrazas(this.archivoTS);
            //Muestro la consola de depuracion
            this.consolaDebug = new Consola();
            this.consolaDebug.createAndShowGUI("*Fuente: " + lex.getNomFichFuente()+ " *Objeto: " + this.sNomFichObjeto);
            //Asigno textAreas a los diferentes objetos para mostrar las trazas en pantalla.
            this.bufferInstr.setTextArea(this.consolaDebug.getTextAreaCodObjeto());
            this.lex.setTextArea(this.consolaDebug.getTextAreaTokens());
            //Cargamos en la consola el contenido del fichero fuente para que se vea.
            this.consolaDebug.getTextAreaCodFuente().setText(this.lex.getCodFuente().toString());
            this.tablaSimbolos.setTextArea(this.consolaDebug.getTextAreaTS());
            this.gestErr.setTextArea(this.consolaDebug.getTextAreaMensajes());
            if (!this.lex.getErrorFicheros().equals(""))
                this.gestErr.escribeError(this.lex.getErrorFicheros());
        }
        //Me posiciono en el primer token
        this.actual = this.lex.siguienteToken();
        try {
            this.programaFin();
        } catch (Exception e) {
            this.emiteCodigo = false;
            e.printStackTrace();
        } finally {
            //Garantizar que el fichero de trazas se cierra siempre
            if (this.bModoTraza){
                this.archivoTrazas.cierraArchivo();
                this.archivoTS.cierraArchivo();
            }
            //Se genera el fichero objeto solamente si no ha habido errores sintácticos
            //incontextuales ni contextuales, o bien si estamos ejecutando en modo traza.
            if ((!this.abortar && this.emiteCodigo) || (this.bModoTraza)) {
                //Abro el fichero objeto de salida.
                ficheroObjeto = new Archivo(this.sNomFichObjeto , Archivo.MODO_ESCRITURA);
                //Recorro el buffer de instrucciones y lo vuelco al archivo.
                Iterator<String> iterador = this.bufferInstr.getBuffer().listIterator();
                while(iterador.hasNext()) {
                    //Escribo cada instruccion en una linea diferente
                    ficheroObjeto.escribe(iterador.next() + "\r\n");
                }
                if (!this.abortar && this.emiteCodigo)
                    this.gestErr.escribeError("Traducción finalizada con éxito. Generado archivo de código objeto.");
                else
                    this.gestErr.escribeError("Se han encontrado errores. Generado archivo de código objeto para depuración.");
                //Cerramos el arhivo.
                ficheroObjeto.cierraArchivo();
            } else {
                this.gestErr.escribeError("El archivo de código objeto no se ha generado porque se han encontrado errores.");
            }
        }

    }
    
    //{Pfin::=P fin}
    private void programaFin () {
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Pfin ::= P fin}" );
        this.programa();
        if (!this.abortar) {
            this.reconoce("fin");
        }
    }

    //{P::=SecDecAmp & SecIns} y {SecDecAmp ::= SecDec | Vacio} fusionadas
    private void programa(){
        Resultado resD;
        Resultado resI;
        String dirEst;
        String instrMP;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{P::= SecDecAmp & SecIns}" );
        if (this.actual.getTipoToken().equals("&")) {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecDecAmp ::= Vacio}" );
            this.reconoce("&");
            if (!this.abortar) {
                instrMP = "seg(0)";
                //instrMP es la 1ª instrucción, que le dice a la MP qué tamaño tiene la memoria estática
                //A partir de dirEst+1, empezará el montículo (de momento)
                this.bufferInstr.emite(instrMP);
                //LA NUMERACION DE INSTRUCCIONES LA LLEVA AHORA AUTOMATICAMENTE el bufferInstr
//                this.etq = 1;//Iniciacizo a 1 el contador de instrucciones, pues ya he emitido 1.
                resI = this.instrucciones();//La tabla de símbolos es un atributo global
                if (!this.abortar) {
                    /*{P.error = D.error v I.error
                     * P.cod = I.cod || stop
                     */
                    this.error = resI.getError();
                    this.bufferInstr.emite("stop");
                    //Debemos asegurarnos antes de generar codigo que tampoco haya habido ningun error contextual.
                    this.emiteCodigo = !this.error;
                }
            }
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecDecAmp ::= SecDec}" );
            //instrMP es la 1ª instrucción, que le dice a la MP qué tamaño tiene la memoria estática
            //Ahora es obligatorio ponerla al principio aunque no sepamos todavía el tamaño exacto, ya que los procedimientos
            //generan instrucciones de código en la seccion de declaraciones. Después la parchearemos con el
            //tamaño de memoria estática que sea necesario.
            //A partir de dirEst+1, empezará el montículo (de momento)
            instrMP = "seg(?)";
            this.bufferInstr.emite(instrMP);
            resD = this.declaraciones(0);
            //Actualizamos el valor correcto de la primera instrucción (seg).
            this.bufferInstr.parchea(1, resD.getDir());
            if (resD.getPend().size()!=0) {
                this.emiteCodigo = false;
                this.gestErr.escribeError("ERROR EN LAS DECLARACIONES : No se han definido uno o más tipos base.");
                resD.setError(true);
            }
            if (!this.abortar){
                this.reconoce("&");
                if (!this.abortar) {
                    //{I.tsh = D.ts}
//                    dirEst = String.valueOf(resD.getDir());
//                    instrMP = ("seg").concat("(").concat(dirEst).concat(")");
                    //instrMP es la 1ª instrucción, que le dice a la MP qué tamaño tiene la memoria estática
                    //A partir de dirEst+1, empezará el montículo (de momento)
//                    this.bufferInstr.emite(instrMP);
                    //LA NUMERACION DE INSTRUCCIONES LA LLEVA AHORA AUTOMATICAMENTE el bufferInstr
    //                this.etq = 1;//Iniciacizo a 1 el contador de instrucciones, pues ya he emitido 1.
                    resI = this.instrucciones();//La tabla de símbolos es un atributo global
                    if (!this.abortar) {
                        /*{P.error = D.error v I.error
                         * P.cod = I.cod || stop
                         */
                        this.error = resD.getError() || resI.getError() || resD.getPend().size()!=0;
    //                    if (this.emiteCodigo) {
                            this.bufferInstr.emite("stop");
    //                        this.etq++;
                            //Debemos asegurarnos antes de generar codigo que no haya habido ningun error contextual.
                            this.emiteCodigo = !this.error;
    //                    }
                    }
                }
            }
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
    }

    //{SecDec::= Dec RSecDec}
    private Resultado declaraciones(int dir){

        Resultado resD;
        Resultado resResto;
        CampoTS elemTS;
        ExprTipos tipoAct;
        int iNumFila, iNumCol;
        int dirAct;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecDec::= Dec RSecDec}" );
        //Guardo la posición de lectura por si hay que dar un mensaje de error
        iNumFila = this.actual.getNumFila();
        iNumCol = this.actual.getNumColumna();
        resD = this.declaracion(dir);
        if (!abortar){
            /*if (resD.getTipoComp().getClase().equals(CLASE_ID_TIPO)){
                int pos = resD.getPend().indexOf(resD.getIdentificador());
                resD.getPend().remove(pos);//Ojo con esto,que no sé yo
            }*/
            //Restricciones contextuales.
            boolean palRes = this.esPalRes(resD.getIdentificador());
            boolean existeEnNivAct = this.existeIDenTSNivAct(resD.getIdentificador());
            if (!resD.getError() && !existeEnNivAct && !palRes){
                String id = resD.getIdentificador();
                tipoAct = resD.getTipoComp();
                dirAct = resD.getDir();
                //{RD.idh = Dec.id}
                //Aquí es donde añado el nuevo elemento a la tabla de símbolos
                elemTS = new CampoTS(id,tipoAct,dirAct,resD.getTipoComp().getClase());
                this.tablaSimbolos.put(elemTS.getId(), elemTS);
            } else if (palRes){
                this.errorPalabraReservada(resD.getIdentificador(), iNumFila, iNumCol);
                dirAct = resD.getDir();
                tipoAct = new Simple("terror");
            } else if(existeEnNivAct){
                this.errorVariableDuplicada(resD.getIdentificador(), iNumFila, iNumCol);
                dirAct = resD.getDir();
                tipoAct = new Simple("terror");
            } else if (this.referenciaErronea(resD.getTipoComp())){
                this.errorTipoErroneo(resD.getIdentificador(), iNumFila, iNumCol);
                dirAct = resD.getDir();
                tipoAct = new Simple("terror");
            }else{
                dirAct = resD.getDir();
                tipoAct = new Simple("terror");
            }
            boolean err = resD.getError() || existeEnNivAct || palRes;
            resResto=this.restoDeclaraciones(err,dirAct,tipoAct,resD.getPend());
            //ArrayList unionPend = juntarPend(resD.getPend(),resResto.getPend());
            //resResto.setPend(unionPend);
            /*{D.error = RD.error
             * D.dir = RD.dir
             * D.ts = RD.ts}
             */
            //resResto.setError(res.getError());
            //resRes.setDir(res.getDir());
        } else {
           resResto = new Resultado();
           resResto.setError(true);//Aquí sí interesa hacerlo así
        }
        //La tabla de símbolos es un atributo global
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resResto;
    }

    //{Dec::= DecVar | DecTipo | DecProc}
    private Resultado declaracion(int dir){
        Resultado resDeclaracion;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Dec::= DecVar | DecTipo | DecProc}" );
        if(this.actual.getLexema().equals("tipo")){
            resDeclaracion = this.declaracionTipo();
            resDeclaracion.getTipoComp().setClase(CLASE_ID_TIPO);
            resDeclaracion.setDir(dir);
        } else if(this.actual.getLexema().equals("procedure")){
            //Aqui SI se modifica dir porque se hacen inserciones en la TS.
            resDeclaracion =this.declaracionProc(dir);
            resDeclaracion.getTipoComp().setClase(CLASE_ID_PROC);
        } else {
            resDeclaracion =this.declaracionVar();
            resDeclaracion.getTipoComp().setClase(CLASE_ID_VAR_PAR_VALOR);
            resDeclaracion.setDir(dir);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resDeclaracion;
    }

    //{DecTipo ::= tipo id = Tipo}
    private Resultado declaracionTipo(){
        Resultado resDeclaracionTipo;
        Resultado resTipo;
        boolean errorTipo;
        String id;
        this.reconoce("palRes","tipo");
        id = this.actual.getLexema();
        this.reconoce("identificador");
        this.reconoce("=");
        resTipo = this.tipo();
        resDeclaracionTipo = new Resultado();
        resDeclaracionTipo.setIdentificador(id);
        resDeclaracionTipo.setTipo(resTipo.getTipoComp());
        errorTipo = resTipo.getError() || this.existeIDenTSNivAct(id) || this.referenciaErronea(resDeclaracionTipo.getTipoComp());
        resDeclaracionTipo.setError(errorTipo);
        return resDeclaracionTipo;
    }

    //{DecVar::= id : Tipo}
    private Resultado declaracionVar (){
        Resultado resDeclaracion;
        String id;
        String tipoPalRes,tipoTrad;
        boolean errorDecVar;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{DecVar::= id : Tipo}" );
        //Siempre hay que devolver un objeto Resultado
        resDeclaracion = new Resultado();
        //Guardo el lexema antes de avanzar la lectura
        id = this.actual.getLexema();
        this.reconoce("identificador");
        if (!abortar){
            this.reconoce(":");
            if (!abortar){
                tipoPalRes = this.actual.getLexema();
                //tipoTrad = this.tipoTraductor(tipoPalRes);
                resDeclaracion = this.tipo();
                errorDecVar = resDeclaracion.getError()||this.existeIDenTSNivAct(id)||this.referenciaErronea(resDeclaracion.getTipoComp());
                if (!abortar){
                    resDeclaracion.setIdentificador(id);
                    resDeclaracion.setError(errorDecVar);
                }
            }
        } else{
            //Activo el error en la regla.
            resDeclaracion.setError(true);
            resDeclaracion.setTipo(new Simple("terror"));
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resDeclaracion;
    }

    //{DecProc ::= procedure id Fparams BloqueProc}
    private Resultado declaracionProc (int dir){
        Resultado resDeclaracionProc, resDeclaracionParamsParen, resBloqueProc;
        String id;
        int iNumFila, iNumCol;
        Procedimiento proc;
        int dirAct;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{DecProc ::= procedure id Fparams BloqueProc}" );
        //Siempre hay que devolver un objeto Resultado
        resDeclaracionProc = new Resultado();
        this.reconoce("palRes", "procedure");   //se reconoce siempre
        if (!abortar){
            //Creo un nuevo nivel en la tabla de símbolos.
            this.tablaSimbolos.creaTSHija();
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            //Guardo el lexema del procedimiento antes de avanzar la lectura
            id = this.actual.getLexema();
            this.reconoce("identificador");
            if (!abortar){
                resDeclaracionParamsParen= this.declaracionParamsParen(dir);
                if (!abortar){
                     //Restricciones contextuales.
                    boolean palRes = this.esPalRes(id);
                    boolean existeEnNivAct = this.existeIDenTSNivAct(id);
                    boolean err = existeEnNivAct || palRes;
                    if (!existeEnNivAct && !palRes){
                        //INSERTAR EN LA TS HIJA LA SIGNATURA DEL PROCEDIMIENTO PARA PERMITIR LLAMADAS RECURSIVAS
                        proc = new Procedimiento("procedure", resDeclaracionParamsParen.getParamsProc());
                        dirAct = resDeclaracionParamsParen.getDir();
                        CampoTS elemTS = new CampoTS(id,proc,dirAct,"proc");
                        //Añadir a la tabla de símbolos en el nivel actual de la TS.
                        this.tablaSimbolos.put(elemTS.getId(), elemTS);
                        dirAct = dirAct + proc.getTam();
                        
                        resDeclaracionProc.setTipo(proc);
                    } else if (palRes){
                        this.errorPalabraReservada(id, iNumFila, iNumCol);
                        dirAct = resDeclaracionParamsParen.getDir();
                    } else {
                        this.errorVariableDuplicada(id, iNumFila, iNumCol);
                        dirAct = resDeclaracionParamsParen.getDir();
                    }
                    if (resDeclaracionParamsParen.getPend().size()!=0) {
                        this.emiteCodigo = false;
                        this.gestErr.escribeError("Error en las declaraciones de los parametros del procedimiento: " + id + ". No se han definido uno o más tipos base.");
                        resDeclaracionParamsParen.setError(true);
                    }
                    //Paso a analizar las instrucciones. Se añaden las declaraciones en la TS hija.
                    resBloqueProc = this.bloqueProc(err, dirAct, id);
                    if (!abortar){
                        if (err | resDeclaracionParamsParen.getError() || resBloqueProc.getError()){
                            resDeclaracionProc.setTipo (new Simple("terror"));
                            resDeclaracionProc.setError(true);
                            resDeclaracionProc.setDir(resBloqueProc.getDir());
                        }else{
                            resDeclaracionProc.setError(false);
//                            resDeclaracionProc.setTipo(proc);
                            resDeclaracionProc.setIdentificador(id);
                            resDeclaracionProc.setDir(resBloqueProc.getDir());
                        }
                    }else{
                        resDeclaracionProc.setTipo (new Simple("terror"));
                        resDeclaracionProc.setError(true);
                        resDeclaracionProc.setDir(resBloqueProc.getDir());
                    }
                    //Desapilo el nivel de la tabla de símbolos que he creado
                    this.tablaSimbolos.desapilaTSHija();
//                    //INSERTAR EN LA TS PADRE EL PROCEDIMIENTO
//                    //JSP: pendiente del calculo de la direccion
//                    elemTS = new CampoTS(id,proc,0,"proc");
//                    //Añadir a la tabla de símbolos en el nivel actual de la TS.
//                    this.tablaSimbolos.put(elemTS.getId(), elemTS);
                } else{
                    //Activo el error en la regla.
                    resDeclaracionProc.setTipo (new Simple("terror"));
                    resDeclaracionProc.setError(true);
                }
            } else{
                //Activo el error en la regla.
                resDeclaracionProc.setTipo (new Simple("terror"));
                resDeclaracionProc.setError(true);
            }
        } else {
            //Activo el error en la regla.
            resDeclaracionProc.setError(true);
            resDeclaracionProc.setTipo (new Simple("terror"));
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resDeclaracionProc;
    }

    //{FParams ::= ( LFParams ) | \}
    private Resultado declaracionParamsParen (int dir){
        Resultado resDeclaracionParamsParen, resDeclaracionParams;
        ArrayList<Parametro> aParams;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{FParams ::= ( LFParams ) | Vacio }" );
        //Siempre hay que devolver un objeto Resultado
        resDeclaracionParamsParen = new Resultado();
        //Inicializo la lista de parametros
        aParams = new ArrayList<Parametro> ();
        if(this.actual.getTipoToken().equals("(")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{LFParamas ::= FParam RLFParams}" );
            this.reconoce("("); //se reconoce siempre
            resDeclaracionParamsParen = this.declaracionParams(dir, aParams);
            if (!abortar){
                this.reconoce(")");
            } else
                //Activo el error en la regla.
                resDeclaracionParamsParen.setError(true);
        } else {
            //Procedimiento sin parámetros.
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{FParams ::= Vacio }" );
            resDeclaracionParamsParen.setParamsProc(aParams);
            resDeclaracionParamsParen.setError(false);
            resDeclaracionParamsParen.setDir(dir);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resDeclaracionParamsParen;
    }

    //{LFParamas ::= FParam RLFParams}
//    private Resultado declaracionParams (int dir, ArrayList pend, ArrayList<Parametro> aParams){
    private Resultado declaracionParams (int dir, ArrayList<Parametro> aParams){
        Resultado resDeclaracionParams, resParametro;
        ExprTipos tipoAct;
        int iNumFila, iNumCol;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{LFParamas ::= FParam RLFParams}" );
        //Siempre hay que devolver un objeto Resultado
        resDeclaracionParams = new Resultado();
        //Guardo la posición de lectura por si hay que dar un mensaje de error
        iNumFila = this.actual.getNumFila();
        iNumCol = this.actual.getNumColumna();
        resParametro = this.parametro();
        if (!abortar){
            //Restricciones contextuales.
            boolean palRes = this.esPalRes(resParametro.getIdentificador());
            boolean existeEnNivAct = this.existeIDenTSNivAct(resParametro.getIdentificador());
            if (!resParametro.getError() && !existeEnNivAct && !palRes){
                boolean err = resParametro.getError();
                String idParam = resParametro.getIdentificador();
                tipoAct = resParametro.getTipoComp();
                String sModo = resParametro.getClaseParam();
                CampoTS elemTS = new CampoTS(idParam,tipoAct,dir, sModo);
                //Añadir a la tabla de símbolos en el nivel actual de la TS.
                this.tablaSimbolos.put(elemTS.getId(), elemTS);
                //Añadir el elemento a la lista de parámetros del procedimiento
                Parametro param = new Parametro(idParam,tipoAct,sModo);
                aParams.add(param);
            } else if (palRes){
                this.errorPalabraReservada(resParametro.getIdentificador(), iNumFila, iNumCol);
                tipoAct = new Simple("terror");
            } else if (existeEnNivAct){
                this.errorVariableDuplicada(resParametro.getIdentificador(), iNumFila, iNumCol);
                tipoAct = new Simple("terror");
            } else if (this.referenciaErronea(resParametro.getTipoComp())){
                this.errorTipoErroneo(resParametro.getIdentificador(), iNumFila, iNumCol);
                tipoAct = new Simple("terror");
            }else{
                tipoAct = new Simple("terror");
            }
            boolean err = resParametro.getError() || existeEnNivAct || palRes;
//            resDeclaracionParams = this.restoListaParams(err, dir, tipoAct, pend, aParams );
            resDeclaracionParams = this.restoListaParams(err, dir, tipoAct, aParams, resParametro.getPend() );
//                resRestoListaParams = this.restoListaParams(err,0,tipoAct,resD.getPend(),sModo);
        } else{
            //Activo el error en la regla.
            resDeclaracionParams.setError(true);
//            resDeclaracionParams.setPend(pend);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resDeclaracionParams;
    }

    //{RLFParamas ::= , FParam RLFParams | \}
//    private Resultado restoListaParams (boolean error,int dir, ExprTipos tipo, ArrayList pend){
    private Resultado restoListaParams (boolean error,int dir, ExprTipos tipo, ArrayList<Parametro> aParam, ArrayList pend){
        Resultado resRestoListaParams, resParametro;
        String id;
        int iNumFila, iNumCol;
        ExprTipos tipoAct;
        int dirAct;
        ArrayList listaPend;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        //Siempre hay que devolver un objeto Resultado
        resRestoListaParams = new Resultado();
        if ( this.actual.getTipoToken().equals(",") ){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RLFParamas ::= , FParam RLFParams}" );
            this.reconoce(","); //se reconoce siempre
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            resParametro = this.parametro();
            if (!abortar){
                //Restricciones contextuales.
                boolean palRes = this.esPalRes(resParametro.getIdentificador());
                boolean existeEnNivAct = this.existeIDenTSNivAct(resParametro.getIdentificador());
                if (!existeEnNivAct && !palRes){
                    String idParam = resParametro.getIdentificador();
                    tipoAct = resParametro.getTipoComp();
                    String sModo = resParametro.getClaseParam();
                    dirAct = dir + tipo.getTam();
                    CampoTS elemTS = new CampoTS(idParam,tipoAct,dirAct,sModo);
                    //Añadir a la tabla de símbolos en el nivel actual de la TS.
                    this.tablaSimbolos.put(elemTS.getId(), elemTS);
                    //Añadir el elemento a la lista de parámetros del procedimiento
                    Parametro param = new Parametro(idParam,tipoAct,sModo);
                    //Se añade el parametro a la lista de parametros
                    aParam.add(param);
                } else if (palRes){
                    this.errorPalabraReservada(resParametro.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                } else if (existeEnNivAct){
                    this.errorVariableDuplicada(resParametro.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                } else if (this.referenciaErronea(resParametro.getTipoComp())){
                    this.errorTipoErroneo(resParametro.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                }else{
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                }
                listaPend = juntarPend(pend,resParametro.getPend());
                boolean err = error | resParametro.getError() || existeEnNivAct || palRes;
                resRestoListaParams = this.restoListaParams(err, dirAct, tipoAct,aParam, listaPend);
            } else{
                //Activo el error en la regla.
                resRestoListaParams.setError(true);
                resRestoListaParams.setDir(dir);
                resRestoListaParams.setTipo(tipo);
            }
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RLFParamas ::= Vacio }" );
            resRestoListaParams.setError(error);
            resRestoListaParams.setParamsProc(aParam);
            resRestoListaParams.setDir(dir + tipo.getTam());
            resRestoListaParams.setTipo(tipo);
            resRestoListaParams.setPend(pend);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoListaParams;
    }

    //{FParam ::= var Tipo id | Tipo id}
    private Resultado parametro (){
        Resultado resTipo, resParametro;
        String id;
        String sModo;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        //Siempre hay que devolver un objeto Resultado
        resParametro = new Resultado();
        if ( this.actual.getLexema().equals("var") ){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{FParam ::= var Tipo id }" );
            this.reconoce("palRes","var"); //se reconoce siempre
            sModo = CLASE_ID_VAR_PAR_VBLE;
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{FParam ::= Tipo id}" );
            sModo = CLASE_ID_VAR_PAR_VALOR;
        }
        
        resParametro = this.tipo();
        if (!abortar){
            //Guardo el nombre del parametro.
            id = this.actual.getLexema();
            this.reconoce("identificador");
            if (!abortar){
                resParametro.setIdentificador(id);
            //JSP: INCLUIR RESTRICCIONES CONTEXTUALES
//            errorDecVar = resDeclaracion.getError()||this.existeID(id)||this.referenciaErronea(resDeclaracion.getTipoComp());
//                resParametro.setError(resTipo.getError());
//                resParametro.setTipo(resTipo.getTipoComp());
                resParametro.setClaseParam (sModo);
            } else{
                //Activo el error en la regla.
                resParametro.setError(true);
                resParametro.setTipo(new Simple("terror"));
            }
        } else{
            //Activo el error en la regla.
            resParametro.setError(true);
            resParametro.setTipo(new Simple("terror"));
        }

        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resParametro;
    }

    // {BloqueProc ::= { SecDecAmp & SecIns } | forward } y {SecDecAmp ::= SecDec | Vacio} fusionadas
    private Resultado bloqueProc (boolean error, int dir, String id){
        Resultado resBloqueProc, resDec, resInst;
        int iNumFila, iNumCol;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        //Siempre hay que devolver un objeto Resultado
        resBloqueProc = new Resultado();
        if ( this.actual.getLexema().equals("forward") ){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{BloqueProc ::= forward }" );
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            this.reconoce("palRes", "forward");     //Se reconoce siempre
            String errorContextual;
            this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                        // se inhibe la generación de código.
            errorContextual = this.construirMensajeError(iNumFila, iNumCol, ERR_PROC_CUERPO_DIFERIDO, id);
            this.gestErr.escribeError(errorContextual);
            resBloqueProc.setError(true);
            resBloqueProc.setDir(dir);
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{BloqueProc ::= { SecDecAmp & SecIns } }" );
            this.reconoce("{");
            if (!this.abortar) {
                if (this.actual.getTipoToken().equals("&")) {
                    escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecDecAmp ::= Vacio}" );
                    this.reconoce("&");     //Se reconoce siempre
                    resInst = this.instrucciones();
                    resBloqueProc.setDir(dir);
                    resBloqueProc.setError(error || resInst.getError());
                } else {
                    escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecDecAmp ::= SecDec}" );
                    resDec = this.declaraciones(dir);
                    resBloqueProc.setDir(resDec.getDir());
                    if (!this.abortar) {
                        this.reconoce("&");
                        if (!this.abortar) {
                            resInst = this.instrucciones();
                            resBloqueProc.setError(error || resDec.getError() || resInst.getError());
                        }else{
                            //Activo el error en la regla.
                            resBloqueProc.setError(true);
                        }
                    }else{
                        //Activo el error en la regla.
                        resBloqueProc.setError(true);
                    }
                }
                if (!this.abortar) {
                    this.reconoce("}");
                } else
                    //Activo el error en la regla.
                    resBloqueProc.setError(true);
            } else
                //Activo el error en la regla.
                resBloqueProc.setError(true);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resBloqueProc;
    }

    private Resultado tipo (){
        Resultado resTipo;
        ExprTipos tipoAct;
//        if(this.tipoSimple(this.actual.getTipo())){
//            this.reconoce(this.actual.getLexema());//Para avanzar
//            tipoAct = new Simple(this.actual.getTipo());
//            tipoAct.setDesp(0);
//            tipoAct.setTam(1);
//            resTipo = new Resultado(tipoAct);
//            resTipo.setError(false);
//        } else {
//            if (this.actual.getLexema().equals("array")){
//                this.reconoce("array");
//                resTipo = this.vector();
//            } else {
//                if (this.actual.getLexema().equals("record")){
//                    //procesa registro
//                    this.reconoce("reg");
//                    resTipo = null;//TO DO
//                } else {
//                    if (this.actual.getLexema().equals("->")){
//                        //procesa puntero
//                        this.reconoce("^");
//                        resTipo = this.puntero();
//                    } else {
//                        if (this.actual.getTipo().equals("identificador")){//Aquí se refiere al tipo de token
//                            //Procesa id
//                            resTipo = this.iden();
//                        }
//                        resTipo = new Resultado();
//                        resTipo.setError(true);//Pensar bien esto
//                    }
//                }
//            }
//        }
//        return resTipo;

        //Palabra reservada
        if (this.actual.getTipoToken().equals("palRes")){
            //tipo de datos simple
            if(this.lexemaTipoSimple(this.actual.getLexema()) || this.tipoSimple(this.actual.getLexema())){
                String LexemaTipoSimple = this.actual.getLexema();
                this.tipoID(); //Para avanzar
                //¿¿¿Qué se le pasa al constructor integer o int????
                tipoAct = new Simple(LexemaTipoSimple);
                tipoAct.setDesp(0);
                tipoAct.setTam(1);
                resTipo = new Resultado(tipoAct);
            } else {
                if (this.actual.getLexema().equals("array")){
                    this.reconoce("palRes", "array");
                    resTipo = this.vector();
                } else {
                    if (this.actual.getLexema().equals("record")){
                        //procesa registro
                        this.reconoce("palRes", "record");
                        resTipo = this.registro();
                    } else if (this.actual.getLexema().equals("pointer")){
                            //procesa puntero
                            this.reconoce("palRes", "pointer");
                            resTipo = this.puntero();
                    } else {
                        //Hemos leido una palabra reservada que no debería venir aqui
                        resTipo= new Resultado();
                        resTipo.setError(true);
                    }
                }
            }
        } else {
            //Tipo puntero
            /*if (this.actual.getTipoToken().equals("->")){
                //procesa puntero
                this.reconoce("palRes", "->");
                resTipo = this.puntero();
            } else {*/
                //identificador de tipo construido
                if (this.actual.getTipoToken().equals("identificador")){//Aquí se refiere al tipo de token
                    //Procesa id
                    resTipo = this.iden();
                } else {
                    if (this.tipoSimple(this.actual.getTipoToken())){
                        tipoAct = new Simple(this.actual.getTipoToken());
                    } else {
                        tipoAct = null;
                        //Ya trataré después tipos complejos
                    }
                    resTipo = new Resultado(tipoAct);
                    resTipo.setError(false);//Lo dejo así de momento
                }
            //}
        }
        return resTipo;
    }

    private Resultado vector(){
        Resultado resVector,resTipo;
        ExprTipos vector;
        String tipoTrad;
        boolean errorVector;
        int nElems;
        int tam;
        this.reconoce("[");
        tipoTrad = this.tipoTraductor(this.actual.getTipoToken());
        if (tipoTrad.equals("nat") || tipoTrad.equals("int")){//Recordar que aquí hablamos del tipo del token
            nElems = Integer.parseInt(this.actual.getLexema());
            this.reconoce(this.actual.getTipoToken());
            this.reconoce("]");
            this.reconoce("palRes","of");
            resTipo = this.tipo();
            errorVector = resTipo.getError()||this.referenciaErronea(resTipo.getTipoComp());
            tam = (resTipo.getTipoComp().getTam()) * nElems;
            vector = new Array("array",nElems,resTipo.getTipoComp());
            vector.setTam(tam);
            vector.setDesp(0);
            resVector = new Resultado(vector);
            resVector.setError(errorVector);
        } else {
            vector = new Simple("terror");
            resVector = new Resultado(vector);
            int iNumFila = this.actual.getNumFila();
            int iNumCol = this.actual.getNumColumna();
            String errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_VAR_NO_INT_NAT);
            this.gestErr.escribeError(errorContextual);
            resVector.setError(true);
        }
        return resVector;
    }

    private Resultado registro(){
        Resultado resRegistro;
        boolean erroRegistro;
       // this.reconoce("record");
        this.reconoce("{");
        resRegistro = this.campos();
        this.reconoce("}");
        return resRegistro;
    }

    //{Campos::=Campo RCampos}
    private Resultado campos(){
        Resultado resCampos;
        CampoReg campo;
        ExprTipos regRes;
        boolean errorAct;
        ListaCampos campos,camposRes;
        Hashtable listaCampos;
        campos = new ListaCampos();
        campo = this.campo(0);//Valor neutro 0. En esta primera llamda da igual.
        campos.setTam(campo.getTipo().getTam());
        campos.getCampos().put(campo.getID(),campo);
        errorAct = campo.getError();
        camposRes = this.restoCampos(campos,errorAct,campo.getPend());
        listaCampos = camposRes.getCampos();
        regRes = new Registro ("record",listaCampos,camposRes.getTam());
        //ArrayList unionPend = this.juntarPend(campo.getPend(), camposRes.getPend());
        errorAct = camposRes.getError();
        resCampos = new Resultado (regRes);
        resCampos.setPend(camposRes.getPend());
        resCampos.setError(errorAct);
        return resCampos;
    }

   /* private Registro campo(){
        Registro regAct;
        CampoReg campo;
        campo = this.construirCampo();
        regAct = new Registro("record");
        regAct.getCampos().put(campo.getID(), campo);
        return regAct;
    }*/

    private CampoReg campo(int desp){
        CampoReg resConsCampo;
        Resultado resTipo;
        boolean errorAct =false;
        
        resTipo = this.tipo();
        String id = this.actual.getLexema();
        this.reconoce("identificador");
        //this.reconoce(":");
        if (resTipo.getTipoComp()!=null){
            errorAct = resTipo.getError() || this.referenciaErronea(resTipo.getTipoComp());
        }
        resConsCampo = new CampoReg(id,resTipo.getTipoComp());
        resConsCampo.setError(errorAct);
        resConsCampo.setPend(resTipo.getPend());
        resConsCampo.setDesp(desp);
        return resConsCampo;
    }

    //{Fusionados en un sólo método RCampos::=; Campo RCampos y RCampos::=\}
    private ListaCampos restoCampos(ListaCampos campos, boolean errorAct,ArrayList pend){
        CampoReg campo;
        ListaCampos camposRes;
        boolean errorAux;
        ArrayList unionPend;
        if (this.actual.getTipoToken().equals(";")) {
            this.reconoce(this.actual.getTipoToken());
            if (!this.abortar) {
                campo = this.campo(campos.getTam());
                errorAux = errorAct || campo.getError() || campos.getCampos().containsKey(campo.getID());
                if (!campos.getCampos().containsKey(campo.getID())) {
                    campos.getCampos().put(campo.getID(), campo);
                    campos.setTam(campos.getTam() + campo.getTipo().getTam());
                }
                unionPend = juntarPend(pend, campo.getPend());
                camposRes = this.restoCampos(campos, errorAux, unionPend);
                //errorAct = camposRes.getError();
                //camposRes.serError(errorAct);
                // ArrayList unionPend = this.juntarPend(campo.getPend(), camposRes.getPend());
                //camposRes.setPend(unionPend);
            } else {
                camposRes = campos;
                int iNumFila = this.actual.getNumFila();
                int iNumCol = this.actual.getNumColumna();
                String errorIncontextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_TOKEN_NO_ESPERADO);
            }
        } else {
            camposRes = campos;
        }
        return camposRes;
    }

    private Resultado puntero(){
        Resultado resPuntero,resTipo;
        ExprTipos puntero;
        boolean errorPuntero;
        resTipo = this.tipo();
        errorPuntero = resTipo.getError();
        puntero = new Puntero("puntero",resTipo.getTipoComp());
        puntero.setTam(1);
        puntero.setDesp(0);
        resPuntero = new Resultado(puntero);
        resPuntero.setIdentificador(resPuntero.getIdentificador());
        resPuntero.setError(errorPuntero);
        resPuntero.setPend(resTipo.getPend());
        return resPuntero;
    }

    private Resultado iden(){
        Resultado resIden;
        ExprTipos iden;
        CampoTS datoTS;
        boolean errorIden;
        String id = this.actual.getLexema();
        this.reconoce("identificador");
        if (this.existeID(id)){
            datoTS = (CampoTS)this.tablaSimbolos.get(id);
            errorIden = !datoTS.getTipoComp().getClase().equals(CLASE_ID_TIPO);
            int tam = datoTS.getTipoComp().getTam();
            iden = new IdTipo("ref",id);
            iden.setDesp(0);
            iden.setTam(tam);
            resIden = new Resultado(iden);
            resIden.setIdentificador(id);
        } else{
        
            iden = new IdTipo("ref",id);
            iden.setTam(1);
            iden.setDesp(0);
            resIden = new Resultado(iden);
            resIden.getPend().add(id);
            resIden.setIdentificador(id);

        }
        
        return resIden;
    }

    private String tipoTraductor(String tipoPalRes){
        String res=tipoPalRes;
        if (tipoPalRes.equals("natural")){
            res = "nat";
        } else if (tipoPalRes.equals("float")){
            res = "real";
        } else if (tipoPalRes.equals("character")){
            res = "car";
        } else if (tipoPalRes.equals("boolean")){
            res = "boolean";//este queda igual
        } else if (tipoPalRes.equals("integer")){
            res = "integer";//este queda igual
        }
        return res;
    }

    /**
     * Reconoce si el token actual corresponde a una palabra reservada con los tipos de datos
     * (integer, float, etc). 
     * El tipo es un subconjunto del token PalRes. Para en este caso saber
     * qué palabra reservada es en concreto, y ver si cae dentro de ese tipo,
     * hay que consultar su lexema.
     * Si se produce coincidencia se avanza la lectura al siguiente token, pero si no coinciden 
     * se produce un error sintáctico que se indica activando una variable global de error.
     * @param tipoToken
     */
     private void tipoID(){
         String errorSintaxis;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
         if (!this.abortar) {
             boolean cond = this.actual.getLexema().equals("natural")
                     || this.actual.getLexema().equals("float") || this.actual.getLexema().equals("character")
                     || this.actual.getLexema().equals("boolean") || this.actual.getLexema().equals("integer");
             /*Parece que la palabra reservada para variables reales es "float", mientras que
              * el tipo real genera el token (real,lexema).
              */
             if (cond) {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "---> Lex: " + this.actual.getLexema() );
                 this.actual = this.lex.siguienteToken();
             } else {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "ERROR ---> Lex: " + this.actual.getLexema() );
                 this.abortar=true;
                errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                    ERR_SE_ESPERABA_TIPO, this.actual.getLexema());                 
                this.gestErr.escribeError(errorSintaxis);
             }
         }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        //Ojo: Aquí igual que en la función reconoce,deberemos devolver un boolean para que aborte en caso
        //de error.
    }

    private void tipoIO(){
       /* El tipo IO es un subconjunto del token PalRes. Para en este caso saber
        * qué palabra reservada es en concreto, y ver si cae dentro de ese tipo,
        * hay que consultar su lexema.
        */
        if (!this.abortar){
            boolean cond = this.actual.getLexema().equals("in") || this.actual.getLexema().equals("out");
            if (cond) {
                this.actual = this.lex.siguienteToken();
            } else {
                 this.abortar=true;
                 String mensajeError = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                ERR_INST_E_S);                         
//                 this.gestErr.escribeError("ERROR : ¡¡¡Programa incorrecto!!! Error en instrucción de entrada/salida");
                 this.gestErr.escribeError(mensajeError);
             }
        }
    }

    private void tipoBloque(){
        /* El tipo Bloque es un subconjunto del token PalRes. Para en este caso saber
        * qué palabra reservada es en concreto, y ver si cae dentro de ese tipo,
        * hay que consultar su lexema.
        */
        if (!this.abortar){
            boolean cond = this.actual.getLexema().equals("{") || this.actual.getLexema().equals("}");
            if (cond) {
                this.actual = this.lex.siguienteToken();
            } else {
                 this.abortar=true;
                 String mensajeError = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                ERR_BLOQUE_INST);                         
//                 this.gestErr.escribeError("ERROR : ¡¡¡Programa incorrecto!!! Error en bloque de instrucciones");
                 this.gestErr.escribeError(mensajeError);
             }
        }
    }

    private String tipoOp (){
        String tipoOperador;
        String operador;
        boolean conv;
        if (this.actual.getTipoToken().equals("palRes")){
            operador = this.actual.getLexema();
        }else{
            operador = this.actual.getTipoToken();
        }
        
        if (operador.equals("not") || operador.equals("-") || operador.equals("+")){
            //this.reconoce(operador);//Para que consuma el token que ya se sabe que lo va a reconocer
            operador = "opLog";
        } else {
            conv = opConv();
            if (conv) {
                operador = "opConv";
            } else operador ="";//Ojo aquí
        }
        return operador;
    }

    private boolean opConv(){
        boolean resultado;
        resultado = this.lex.getListaPalConv().containsKey(this.actual.getLexema());
        return resultado;
   }

    //Fusionados en un sólo método {RSec_Dec::= \ y RSec_Dec::=;Dec RSec_Dec}
    private Resultado restoDeclaraciones(boolean error,int dir, ExprTipos tipo, ArrayList pend){

        Resultado resDec;
        Resultado rSec_Dec;
        ExprTipos tipoAct;
        //Resultado resRestoDec = new Resultado();
        CampoTS elemTS;
        boolean palRes=false;
        boolean err = false;
        int iNumFila, iNumCol;
        int dirAct;
        ArrayList listaPend,unionPend;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        if (this.actual.getTipoToken().equals(";")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RSec_Dec::= ; Dec RSec_Dec}" );
            this.reconoce(";");//Obviamente, lo va a reconocer
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            dirAct = dir + tipo.getTam();
            resDec=this.declaracion(dirAct);
            if (!abortar){
               /* if (resDec.getTipoComp().getClase().equals(CLASE_ID_TIPO)) {
                    int pos = resDec.getPend().indexOf(resDec.getIdentificador());
                    if (pos!=-1){//Pequeño arreglo de momento
                        resDec.getPend().remove(pos);//Ojo con esto,que no sé yo
                    }
                }*/
                palRes = this.esPalRes(resDec.getIdentificador());
                err = error | resDec.getError() || this.existeIDenTSNivAct(resDec.getIdentificador()) || palRes;
               // resRestoDec.setError(err);
                if (!resDec.getError() && !existeIDenTSNivAct(resDec.getIdentificador()) && !palRes){
//                    dirAct = dir + tipo.getTam();
                    tipoAct = resDec.getTipoComp();
                    elemTS = new CampoTS(resDec.getIdentificador(),resDec.getTipoComp(),resDec.getDir(),resDec.getTipoComp().getClase());
                    this.tablaSimbolos.put(elemTS.getId(), elemTS);
                    //Comprobar pendientes
                } else if (palRes){
                    this.errorPalabraReservada(resDec.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                } else if (existeIDenTSNivAct(resDec.getIdentificador())){
                    this.errorVariableDuplicada(resDec.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                } else if (this.referenciaErronea(resDec.getTipoComp())){
                    this.errorTipoErroneo(resDec.getIdentificador(), iNumFila, iNumCol);
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                }else{
                    dirAct = dir;
                    tipoAct = new Simple("terror");
                }
                unionPend = juntarPend(pend,resDec.getPend());
                if (resDec.getTipoComp().getClase().equals(CLASE_ID_TIPO)){
                    listaPend = eliminarPendiente(unionPend,resDec.getIdentificador());
                } else{
                    listaPend = unionPend;
                }
                rSec_Dec = this.restoDeclaraciones(err,resDec.getDir(),tipoAct,listaPend);
                //ArrayList unionPend = juntarPend(resDec.getPend(),rSec_Dec.getPend());
                //rSec_Dec.setPend(unionPend);
            } else {
                //Creo que no haría falta pero por si las flies...
                rSec_Dec = new Resultado();
                rSec_Dec.setError(true);
            }
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RSec_Dec::= Vacío}" );
            rSec_Dec = new Resultado(tipo);
            rSec_Dec.setPend(pend);
            rSec_Dec.setDir(dir + tipo.getTam());
            rSec_Dec.setError(error);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return rSec_Dec;
    }

    //{SecIns::= Ins RSec_Ins}
    private Resultado instrucciones(){
        Resultado resInst;
        Resultado resRestoInst;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{SecIns::= Ins RSec_Ins}");
        resInst = this.instruccion();
        if (!this.abortar) {
            resRestoInst = this.restoInstrucciones(resInst.getError());
            resInst.setError(resRestoInst.getError());
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resInst; 
    }

    //{Inst::= InstLec | InstEsc | InstAsig | IComp | IBloque | InsIf | InsWhile | InsFor | INew | IDel}
    private Resultado instruccion(){
        Resultado res;
        String errorSintaxis,numLin,numCol;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        /* in es una palabra reservada. Debo consultar su lexema, para saber
         * qué tipo de palabra reservada es.
         */
        res =new Resultado();
        if (this.actual.getLexema().equals("in")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Inst::= InstLec" );
            //{Iasig.tsh = Inst.tsh} , pero la ts es global
            res = this.instLectura();
           
        /* out es una palabra reservada. Debo consultar su lexema, para saber
         * qé tipo de palabra reservada es.
         */
        } else if (this.actual.getLexema().equals("out")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Inst::= InstEsc}" );
            res = this.instEscritura();
        //Aquí sin embargo me vale con el tipo
        } else if (this.actual.getTipoToken().equals("identificador")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Inst::= InstAsig}" );
            res = this.instAsig();
        } else if (this.actual.getTipoToken().equals("{")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= IBloque}" );
            res = this.instBloque();
        } else if (this.actual.getLexema().equals("if")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= InsIf}" );
            res = this.instIf();
        } else if (this.actual.getLexema().equals("while")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= InsWhile}" );
            res = this.instWhile();
        } else if (this.actual.getLexema().equals("for")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= InsFor}" );
            res = this.instFor();
        } else if (this.actual.getLexema().equals("new")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= InsNew}" );
            res = this.instNew();
        } else if (this.actual.getLexema().equals("dispose")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins::= InsDel}" );
            res = this.instDel();
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "ERROR ---> " + this.actual.getLexema() );
            res.setError(true);     //por si las flies.
            this.abortar = true;
            errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                    ERR_SE_ESPERABA_INST, this.actual.getTipoToken() + " y lexema: " +this.actual.getLexema());  
            this.gestErr.escribeError(errorSintaxis);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return res;
    }

    //Fusionados en un solo método {RSec_Ins::= \ y RSec_Ins::=;Ins RSec_Ins}
    private Resultado restoInstrucciones(boolean error){
        Resultado resRestoInst;
        Resultado resInst;
        String codMP;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        boolean err = false;
        if (this.actual.getTipoToken().equals(";")){//{R::=;I}
            //escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoInstrucciones::= ;I}" );
            //{I.tsh = RI.tsh} pero la ts es global
            this.reconoce(";");
            resInst =this.instrucciones();
            /*{RI.error = RI.errorh v I.error
             * RI.cod = RI.codh || I.cod}
             */
            err = error || resInst.getError();
            resRestoInst = this.restoInstrucciones(err);
            //Como cod es una variable global, aquí ahora no se hace nada.
        } else {//{R::=\}
            //escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoInstrucciones::= Vacío}" );
            resRestoInst = new Resultado();
            resRestoInst.setError(error);
            //this.reconoce("fin");//Para que no acepte máscosa
            //cod variable global. No se hace nada.
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoInst;
    }

    //{InstLec::= in(iden)}
    private Resultado instLectura(){
        Resultado resLec;
        CampoTS datoTS;
        String identificador,tipoID;
        String instrMP;
        String cadenaDir;
        resLec = new Resultado();
        String errorContextual;
        int iNumFila, iNumCol;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{InstLec::= in(iden)}" );
        this.tipoIO();//Si estoy aquí, es que lo va a reconocer
        this.reconoce("(");
        if (!this.abortar){
            identificador = this.actual.getLexema();
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            this.reconoce("identificador");
            if (!this.abortar){
                //Accedo a la Tabla de símbolos una vez
                //reconocido el token como un identificador
                if (this.existeID(identificador)){
                    datoTS = (CampoTS)this.tablaSimbolos.get(identificador);
                    tipoID = datoTS.getTipo();
                    instrMP=this.generaCodigoOpLectura(tipoID);
                    //Antes la condición era !this.abortar. Cuidado por si he metido la pata al cambiarlo
//                    if (this.emiteCodigo){
                        this.bufferInstr.emite(instrMP);
////                        this.etq ++;
//                    }
                    cadenaDir = String.valueOf(datoTS.getDir());
                    instrMP ="desapila_dir(".concat(cadenaDir).concat(")");
                    //Antes lacondición era !this.abortar. Cuidado por si he metido la pata al cambiarlo
//                    if (this.emiteCodigo){
                        this.bufferInstr.emite(instrMP);
//                        this.etq++;
//                    }
                }else{
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                            // se inhibe la generación de código.
                    errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                        ERR_VAR_NO_DECLARADA, identificador);
                    this.gestErr.escribeError(errorContextual);
                }
                this.reconoce(")");
                if (this.abortar)
                    resLec.setError(true);
            } else
                resLec.setError(true);
        } else
            resLec.setError(true);
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resLec;
    }

    //{InstEsc::= out(Expresion)}
    private Resultado instEscritura(){
        Resultado resEsc,E;
        boolean errorEsc;
        CampoTS datoTS;
        String identificador,tipoID,dir;
        String instrMP;
        String cadenaDir;
        resEsc = new Resultado();
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{InstEsc::= out(Expresion)}" );
        this.tipoIO();//Si estoy aquí, es que lo va a reconocer
        this.reconoce("(");
        if (!this.abortar){
            E = this.expresion();
            if (!this.abortar){
                // errorEsc = !existeID(identificador);
                resEsc.setError(E.getError());
                instrMP=this.generaCodigoOpEscritura(E.getTipo());
                if (instrMP.equals("out_dir")){
                    if (this.existeID(E.getIdentificador())) {
                        datoTS = (CampoTS) this.tablaSimbolos.get(E.getIdentificador());
                        dir = String.valueOf(datoTS.getDir());
                        instrMP = instrMP.concat("(").concat(dir).concat(")");
                    }else {
                        this.emiteCodigo=false;
                    }
                }
                //Antes lacondición era !this.abortar. Cuidado por si he metido la pata al cambiarlo

                //cadenaDir = String.valueOf(datoTS.getDir());
                //instrMP ="desapila_dir(".concat(cadenaDir).concat(")");
                //Antes lacondición era !this.abortar. Cuidado por si he metido la pata al cambiarlo
//                if (this.emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
//                }
                this.reconoce(")");
                if(this.abortar)
                    resEsc.setError (true);
            } else
                resEsc.setError (true);
        } else
            resEsc.setError (true);
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resEsc;
    }

    //{InstAsig::= Mem := Expresion}
    private Resultado instAsig(){
        Resultado resInstAsig;
        Resultado resMem;
        Resultado resExpr;
        String id;
        String instrMP,instrMPCasting;
        String cadenaDir;
        String tipoID="";
        String tipoExp ="";
        String errorContextual,numLin,numCol;
        int dir;
        boolean errAsig;
        boolean errTipo;
        boolean tiposAsig;
        CampoTS datoTS;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{InstAsig::= Mem := Expresion}" );
        id = this.actual.getLexema();
        //this.reconoce("identificador"); //Si se ha entrado aqui entonces se reconoce siempre.
        /*if (this.existeID(id)) {
            datoTS = (CampoTS) this.tablaSimbolos.get(id);
            tipoID = datoTS.getTipo();
        } else {
            this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
            numLin = this.actual.getNumFila()+" ";//Automáticamente casting a String
            numCol = this.actual.getNumColumna()+" ";
            errorContextual =
               ("ERROR SINTÁCTICO CONTEXTUAL en línea ").concat(numLin)
               .concat("y columna ").concat(numCol).concat(" . La variable ")
               .concat(id).concat(" no ha sido declarada.")
               ;
            this.gestErr.escribeError(errorContextual);

        }*/
        resMem = this.mem();
        this.reconoce(":=");
        //{E.tsh = Iasig.tsh} pero ts es variable global
        resInstAsig = new Resultado();
        if (!this.abortar) {
            resExpr = this.expresion();
            if (!this.abortar) {
                errAsig = !(this.compatiblesComp(resMem.getTipoComp(), resExpr.getTipoComp()));
                if (!errAsig) {
                    tipoID = this.tipoTraductor(resMem.getTipoComp().getTipo());
                    tipoExp = this.tipoTraductor(resExpr.getTipoComp().getTipo());
                    instrMPCasting = this.castingTipos(tipoID, tipoExp);
                    if (this.existeID(id)){
                        datoTS = (CampoTS) this.tablaSimbolos.get(id);
                        dir = datoTS.getDir();
                        cadenaDir = String.valueOf(dir);
                    }
                    //instrMP = "desapila_dir(".concat(cadenaDir).concat(")");
                    String tipoTrad = this.tipoTraductor(resExpr.getTipoComp().getTipo());
                    if (this.tipoSimple(tipoTrad)) {
                        instrMP = "desapila_ind";
//                    if (this.emiteCodigo) {
                        if (!instrMPCasting.equals("")) {
                            this.bufferInstr.emite(instrMPCasting);
//                            this.etq++;
                        }
                        this.bufferInstr.emite(instrMP);
//                        this.etq++;
//                    }
                    }
                    resInstAsig.setTipo(resMem.getTipoComp());//Así de momento para hacer una prueba
                    resInstAsig.setError(errAsig);
                } else {
                    resInstAsig.setError(errAsig);
                }
            } else {
                resInstAsig.setError(true);
            }
        } else {
            resInstAsig.setError(true);
        }
                //errTipo = (resExpr.getTipo().equals("terror"));
                /*if (this.existeID(id)) {
                    if (resExpr.getTipo().equals("identificador")){
                        tipoExp = this.tipoID(resExpr.getIdentificador());
                    } else
                        tipoExp = resExpr.getTipo();
                    tiposAsig = tiposAsignacion(tipoID,tipoExp);
                } else 
                    //La variable no ha sido declarada. Pongo esta variable a true
                    //para que no salte el error de tipos incompatibles.
                    tiposAsig = true;
                //Mostramos el mensaje de incompatibilidad de tipos en la asignación 
                //solo si corresponde.
                if ((tipoExp.compareTo("terror") != 0) && !tiposAsig )
                    this.errorTiposAsig();
                errAsig = errTipo || !this.existeID(id) || !tiposAsig;
                resInstAsig.setError(errAsig);
                if (!errAsig) {
                    instrMPCasting = this.castingTipos(tipoID,resExpr.getTipo());
                    datoTS = (CampoTS) this.tablaSimbolos.get(id);
                    dir = datoTS.getDir();
                    cadenaDir = String.valueOf(dir);
                    instrMP = "desapila_dir(".concat(cadenaDir).concat(")");
                    if (this.emiteCodigo) {
                        if (!instrMPCasting.equals("")) {
                            this.bufferInstr.emite(instrMPCasting);
//                            this.etq++;
                        }
                        this.bufferInstr.emite(instrMP);
//                        this.etq++;
                    }
                } 
            } else {
                resInstAsig.setError(true);
            }
        } else
            resInstAsig.setError(true);

        */
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resInstAsig;
    }

   /* private Resultado mem(){
        Resultado resMem;
        ExprTipos tipoAct = null;
        CampoTS datoTS = null;
        if (this.actual.getTipo().equals("identificador")){
            String id = this.actual.getLexema();
            this.reconoce(id);
            if (this.existeID(id)){
                 datoTS= (CampoTS)this.tablaSimbolos.get(id);
                if (datoTS.getClase().equals(CLASE_ID_VAR_PAR_VALOR)){
                    tipoAct = this.refAlias(datoTS.getTipoComp());
                } else tipoAct = new Simple("terror");
            } else tipoAct = new Simple("terror");
            String dir = String.valueOf(datoTS.getDir());
            String instrMP = ("apila_dir").concat("(").concat(dir).concat(")");
            this.bufferInstruc.emite(instrMP);
            this.etq++;
        }
        resMem = new Resultado(tipoAct);
        return resMem;//Luego continuará
    }*/

    //{Mem::=id RMem}
    private Resultado mem(){//Es sólo un esbozo de momento
        Resultado resMem;
        CampoTS datoTS;
        ExprTipos tipoAct;
        int valor;
        int iNumFila, iNumCol;
        String id = this.actual.getLexema();
       // this.reconoce("identificador");
        if (this.existeID(id)) {
            datoTS = (CampoTS) this.tablaSimbolos.get(id);
            valor = datoTS.getDir();
            tipoAct = this.refAlias(datoTS.getTipoComp());
            resMem = this.resMem(tipoAct, valor);
        } else {
            //Guardo la posición de lectura por si hay que dar un mensaje de error
            iNumFila = this.actual.getNumFila();
            iNumCol = this.actual.getNumColumna();
            this.reconoce("identificador");//Para que avance
            tipoAct = new Simple("terror");
            resMem = new Resultado(tipoAct);
            this.errorVarNoDeclarada(id, iNumFila, iNumCol);
            resMem.setError(true);
        }
        return resMem;
    }

    //{RMem ::= FFMem RMem | \, donde FFMem ::= FMem | [Exp] y FMem ::= -> | .id
    // todo fusionado en el mismo método}
    private Resultado resMem(ExprTipos e,int valor) {
        Resultado resResMem;
        ExprTipos eAct;
        String instrMP;
        String ind;
        CampoTS datoTS;
        int dir;
        if (this.actual.getTipoToken().equals("[")) {
            this.reconoce(this.actual.getTipoToken());
            ind = this.actual.getLexema();
            resResMem = this.expresion();
            this.reconoce("]");
            String tipoTrad = this.tipoTraductor(resResMem.getTipoComp().getTipo());
            if (e.getTipo().equals("array") && (tipoTrad.equals("nat") || tipoTrad.equals("integer"))) {
                Array vector = (Array) e;
                eAct = this.refAlias(vector.getTipoBase());
                String tamBase = String.valueOf(vector.getTipoBase().getTam());
                instrMP = ("apila").concat("(").concat(tamBase).concat(")");
                this.bufferInstr.emite(instrMP);
                instrMP = "multiplica";
                this.bufferInstr.emite(instrMP);
                instrMP = "suma";
                this.bufferInstr.emite(instrMP);
                resResMem = this.resMem(eAct,vector.getTipoBase().getTam());
            } else {
                eAct = new Simple("terror");
                resResMem = new Resultado(eAct);
            }
        } else if (this.actual.getTipoToken().equals("->")) {
            this.reconoce(this.actual.getTipoToken());
            if (e.getTipo().equals("puntero")) {
                Puntero puntero = (Puntero) e;
                eAct = this.refAlias(puntero.getTipoBase());
                instrMP = "apila_ind";
                this.bufferInstr.emite(instrMP);
                resResMem = this.resMem(eAct,valor);//En el caso del puntero el segundo campo no es relevante
            } else {
                eAct = new Simple("terror");
                resResMem = new Resultado(eAct);
            }
        } else if (this.actual.getTipoToken().equals(".")) {
            this.reconoce(this.actual.getTipoToken());
            String id = this.actual.getLexema();
            this.reconoce("identificador");
            if (e.getTipo().equals("record")) {
                Registro reg = (Registro) e;
                if (reg.getCampos().containsKey(id)) {
                    CampoReg campo = (CampoReg) reg.getCampos().get(id);
                    eAct = this.refAlias(campo.getTipo());
                    String desp = String.valueOf(campo.getDesp());
                    instrMP = ("apila").concat("(").concat(desp).concat(")");
                    this.bufferInstr.emite(instrMP);
                    instrMP = "suma";
                    this.bufferInstr.emite(instrMP);
                    resResMem = this.resMem(eAct,campo.getTipo().getDesp());
                } else {
                    eAct = new Simple("terror");
                    resResMem = new Resultado(eAct);
                }
            } else {
                eAct = new Simple("terror");
                resResMem = new Resultado(eAct);
            }

        } else if (this.actual.getTipoToken().equals("identificador")) {
            String val = String.valueOf(valor);
           // String val = this.actual.getLexema();
            String id = this.actual.getLexema();
            instrMP = ("apila").concat("(").concat(val).concat(")");
            this.bufferInstr.emite(instrMP);
            //this.reconoce(this.actual.getTipoToken());//Paraque avance
            datoTS = (CampoTS)this.tablaSimbolos.get(id);
            dir = datoTS.getDir();
            eAct = this.refAlias(datoTS.getTipoComp());
            this.reconoce(this.actual.getTipoToken());//Para que avance
            resResMem = this.resMem(eAct, dir);
        } else {
            //eAct = new Simple("terror");
            resResMem = new Resultado(e);
        }
        return resResMem;
    }

    //{Fusionados ISBloque e IOpc}
    private Resultado instBloque(){
        Resultado resBloque;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        this.reconoce("{");     //Se reconoce siempre
        
        //OJO: NO SE PERMITEN BLOQUES DE INSTRUCCIONES VACIAS.
//        if (this.actual.getTipoToken().equals("}")){
//            escribeFichTrazasSiModoTraza (this.iNivelProf, "{ISBloque::= IOpc} y {IOpc::= Vacio}" );
//            this.reconoce("}");//Para que avance
//            resBloque = new Resultado();
//            resBloque.setError(false);
//        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{ISBloque::= IOpc} y {IOpc::= SecIns}" );
            resBloque = this.instrucciones();
            if (!this.abortar)
                this.reconoce("}");
            else
                resBloque.setError(true);
//        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resBloque;
    }

    //{InsIf::= if Expresion then Inst PElse}
    private Resultado instIf(){
        Resultado resIf, resExpr, resInst, resPelse;
        int etqSaltoCondicion;
        int iNumFila, iNumCol;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{InsIf::= if Expresion then Inst PElse}" );
        resIf = new Resultado();
        this.reconoce("palRes", "if");  //El if se reconoce siempre
        //Guardo la posición de lectura por si hay que dar un mensaje de error
        iNumFila = this.actual.getNumFila();
        iNumCol = this.actual.getNumColumna();
        resExpr = this.expresion();
        if (!this.abortar){
            this.reconoce("palRes", "then");
            if (!this.abortar){
                //Guardo el numero de la proxima instruccion que se va a escribir (la del salto)
                etqSaltoCondicion = bufferInstr.getEtq();
                this.bufferInstr.emite("ir-f(?)");
                resInst = this.instruccion();
//                resInst = this.instrucciones();
                if (!this.abortar){
                    resPelse = this.pElse();
                    String tipoExpr = resExpr.getTipo();
                    boolean err = !tipoExpr.equals("boolean");
                    if(err){
                        String errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_COND_NO_ES_BOOL);        
                        this.gestErr.escribeError(errorContextual);
                    }
//                    if (err || resInst.getTipo().equals("terror") || resPelse.getTipo().equals("terror")){
                    if (err || resInst.getError() || resPelse.getError()){
                        resIf.setError(true);
                    } else {
                        resIf.setError(false);
                    }
                    //Completamos la instruccion de salto con la direccion correspondiente
                    if (!this.bufferInstr.parchea(etqSaltoCondicion,resPelse.getEtqi())){
                        resIf.setError(true);
                    }
                } else {
                    resIf.setError(true);
                }
            } else {
                resIf.setError(true);
            }
        } else {
            resIf.setError(true);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resIf;
    }

    //{PElse::= else Inst | Vacío}
    private Resultado pElse(){
        Resultado resPElse;
        int etqSaltoADespuesElse, etqInstPrimeraCuerpoElse;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{PElse::= else Inst | Vacío}" );
        if(this.actual.getLexema().equals("else")){
            this.reconoce("palRes", "else");    //se reconoce siempre
            //Guardo el numero de la proxima instruccion que se va a escribir (la del salto)
            etqSaltoADespuesElse = bufferInstr.getEtq();
            this.bufferInstr.emite("ir-a(?)");
            //Guardo el numero de la primera instruccion del 'else' posterior al salto.
            //Hay que retornarsela al 'if' para que pueda completar su código.
            etqInstPrimeraCuerpoElse = bufferInstr.getEtq();
            resPElse = this.instruccion();
            //Devuelvo el numero de la primera instruccion del 'else' posterior al salto
            //dentro del objeto resultado (para poder completar el codigo del if)
            resPElse.setEtqi(etqInstPrimeraCuerpoElse);
            //Completo la instruccion de salto con el numero de la linea que va despues del codigo del else
            if (!this.bufferInstr.parchea(etqSaltoADespuesElse,bufferInstr.getEtq())){
                resPElse.setError(true);
            }
        } else {
            resPElse = new Resultado();
            resPElse.setError(false);
            //Devuelvo el numero de la primera instruccion del 'else' posterior al salto
            //dentro del objeto resultado (para poder completar el codigo del if)
            resPElse.setEtqi(this.bufferInstr.getEtq());
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resPElse;
    }

    //{Ins_While ::= while Exp do Inst}
    private Resultado instWhile(){
        Resultado resWhile;
        Resultado resExp, resInst;
        int iNumFila, iNumCol;
        int etqInstInicioBucle, etqSaltoEvalCondBucle;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins_While ::= while Exp do Inst}" );
        resWhile = new Resultado();
        this.reconoce("palRes", "while"); //se reconoce siempre
        //Guardo la posición de lectura por si hay que dar un mensaje de error
        iNumFila = this.actual.getNumFila();
        iNumCol = this.actual.getNumColumna();
        //Guardamos la direccion de la primera instruccion
        //del bucle.
        etqInstInicioBucle = this.bufferInstr.getEtq();
        resExp = this.expresion();
        if (!this.abortar){
            this.reconoce("palRes", "do");
            if (!this.abortar){
                etqSaltoEvalCondBucle = this.bufferInstr.getEtq();
                this.bufferInstr.emite("ir-f(?)");
                resInst = this.instruccion();
                if (!this.abortar){
                    boolean err = !resExp.getTipo().equals("boolean");
                    if(err){
                        this.emiteCodigo = false;
                        String errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_COND_NO_ES_BOOL);        
                        this.gestErr.escribeError(errorContextual);
                    }
                    if (err || resInst.getError()){
                        resWhile.setError(true);
                    } else{
                        resWhile.setError(false);
                    }
                    String dir = String.valueOf(etqInstInicioBucle);
                    String instr = ("ir-a(").concat(dir).concat(")");
                    this.bufferInstr.emite(instr);
            //        this.etq++;
                    if (!this.bufferInstr.parchea(etqSaltoEvalCondBucle,this.bufferInstr.getEtq())){
                        resWhile.setError(true);
//                        this.abortar = true;
                    }
                } else {
                    resWhile.setError(true);
                }
            } else {
                resWhile.setError(true);
            }
        } else {
            resWhile.setError(true);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resWhile;
    }
    
    //{Ins_For ::= for id:= Exp0 to Exp1 do Inst}
    private Resultado instFor(){
        Resultado resFor;
        Resultado resAsig;
        Resultado resExp0,resExp1,resInst;
        CampoTS datoTS;
        String tipoID,errorContextual,dirID, tipoExp0, tipoExp1;
        tipoID="";
        dirID ="";
        int etqInstActualizVarControl, etqSaltoEvalCondBucle;
        int iNumFila, iNumCol;
        boolean err0=false, err1=false, err2=false ,err3=false, err4= false, err5= false;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Ins_For ::= for id:= Exp0 to Exp1 do Inst}" );
        this.reconoce("palRes", "for");   //se reconoce siempre
        resFor = new Resultado();
        String id = this.actual.getLexema();
        //Guardo la posición de lectura por si hay que dar un mensaje de error
        iNumFila = this.actual.getNumFila();
        iNumCol = this.actual.getNumColumna();
        this.reconoce("identificador");
        if (!this.abortar){
            //Se comprueba si el identificador está en la tabla de símbolos.
            if (this.existeID(id)) {
                datoTS = (CampoTS) this.tablaSimbolos.get(id);
                if (datoTS.getClase().equals(CLASE_ID_VAR_PAR_VALOR)){
                    dirID = String.valueOf(datoTS.getDir());
                    ExprTipos tipoAct = this.refAlias(datoTS.getTipoComp());
                    tipoID = tipoAct.getTipo();
                    tipoID = this.tipoTraductor(tipoID);
                    err1 = !tipoID.equals("nat") && !tipoID.equals("integer");
                    if(err1){
                        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                                // se inhibe la generación de código.
                        errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                                ERR_VAR_NO_INT_NAT, id);
                        this.gestErr.escribeError(errorContextual);
                    }
                }else{
                    err0 = true;
                }
            } else {
                err0 = true;
            }

            if (err0){
                this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                        // se inhibe la generación de código.
                errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                        ERR_VAR_NO_DECLARADA, id);
                this.gestErr.escribeError(errorContextual);
            }
            this.reconoce(":=");
            if (!this.abortar){
                //Guardo la posición de lectura por si hay que dar un mensaje de error
                iNumFila = this.actual.getNumFila();
                iNumCol = this.actual.getNumColumna();
                String Instr = ("apila(").concat(dirID).concat(")");
                this.bufferInstr.emite(Instr);
                resExp0 = this.expresion();
                tipoExp0 = this.tipoTraductor(resExp0.getTipo());
                err2 = !tipoExp0.equals("nat") && !tipoExp0.equals("integer");
                if(err2){
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                            // se inhibe la generación de código.
                    errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                            ERR_EXP_NO_INT_NAT);
                    this.gestErr.escribeError(errorContextual);
                } else {
                    //Si la variable de control ha sido declarada y tiene un tipo adecuado.
                    if (!err0 && !err1) {
                        //Comprobamos la compatibilidad de tipos entre el valor de la expresion y la var. de control del bucle.
                        err4 = !tiposAsignacion (tipoID, tipoExp0);
                        if(err4){
                            this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                                    // se inhibe la generación de código.
                            errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                                    ERR_INCOMP_TIPOS_ASIG);
                            this.gestErr.escribeError(errorContextual);
                        }
                    }
                }
                if (!this.abortar){
                    this.reconoce("palRes", "to");
                    if (!this.abortar) {
                        etqInstActualizVarControl = this.bufferInstr.getEtq();
                        //Se actualiza la variable con el valor de la pila
                        Instr = ("desapila_ind");
                        this.bufferInstr.emite(Instr);
                        //Pongo el valor de la variable de control en la cima
                        Instr = ("apila(").concat(dirID).concat(")");
                        this.bufferInstr.emite(Instr);
                        Instr = ("apila_ind");
                        this.bufferInstr.emite(Instr);
                        //Guardo la posición de lectura por si hay que dar un mensaje de error
                        iNumFila = this.actual.getNumFila();
                        iNumCol = this.actual.getNumColumna();
                        resExp1 = this.expresion();
                        tipoExp1 = this.tipoTraductor(resExp1.getTipo());
                        err3 = !tipoExp1.equals("nat") && !tipoExp1.equals("integer");
                        if(err3){
                            this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                                    // se inhibe la generación de código.
                            errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                                    ERR_EXP_NO_INT_NAT);
                            this.gestErr.escribeError(errorContextual);
                        } else {
                            //Si la variable de control ha sido declarada y tiene un tipo adecuado.
                            if (!err0 && !err1) {
                                //Comprobamos la compatibilidad de tipos entre el valor de la expresion y la var. de control del bucle.
                                err5 = !tiposAsignacion (tipoID, tipoExp1);
                                if(err5){
                                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                                            // se inhibe la generación de código.
                                    errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                                            ERR_INCOMP_TIPOS_ASIG);
                                    this.gestErr.escribeError(errorContextual);
                                }
                            }
                        }
                        if (!this.abortar){
                            this.reconoce("palRes", "do");
                            if (!this.abortar) {
                                this.bufferInstr.emite("menorigual");
                                etqSaltoEvalCondBucle = this.bufferInstr.getEtq();
                                this.bufferInstr.emite("ir-f(?)");
                                resInst = this.instruccion();
                                if (!this.abortar) {
                                    if (err0 || err1 || err2 || err3 || err4 || err5) {
                                        resFor.setError(true);
                                    } else {
                                        resFor.setError(false);
                                    }
                                    //Dejo la direccion de la variable de control preparada en la pila.
                                    Instr = ("apila(").concat(dirID).concat(")");
                                    this.bufferInstr.emite(Instr);
                                    //Generamos el codigo de incremento de la variable.
                                    this.generaCodigoIncrementoVariable(dirID);
                                    //Saltamos a la actualizacion de la variable de control.
                                    String dir = String.valueOf(etqInstActualizVarControl);
                                    Instr = ("ir-a(").concat(dir).concat(")");
                                    this.bufferInstr.emite(Instr);
                                    if (!this.bufferInstr.parchea(etqSaltoEvalCondBucle, this.bufferInstr.getEtq()))
                                        this.abortar = true;                
                                }else
                                    resFor.setError(true);
                            }else
                                resFor.setError(true);
                        }else
                            resFor.setError(true);
                    }else
                        resFor.setError(true);
                }else
                    resFor.setError(true);
            }else
                resFor.setError(true);
        }else
            resFor.setError(true);
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resFor;
    }

    private Resultado instNew() {
        Resultado resNew;
        ExprTipos tAct;
        CampoTS datoTS;
        String instrMP;
        this.reconoce("palRes", "new");
        resNew = this.mem();
        boolean err = !resNew.getTipoComp().getTipo().equals("puntero");
        if (!err) {
            Puntero p = (Puntero)resNew.getTipoComp();
            if (p.getTipoBase().getTipo().equals("ref")) {//Qué te apuestas a que esto no es así...
                //Este bloque va a haber que repasarlo...
                IdTipo id = (IdTipo) p.getTipoBase();
                if (this.existeID(id.getId())) {
                    datoTS = (CampoTS) this.tablaSimbolos.get(id.getId());
                    int tam = datoTS.getTipoComp().getTam();
                    instrMP = "new".concat("(").concat(String.valueOf(tam)).concat(")");
                    this.bufferInstr.emite(instrMP);
                } else {
                    tAct = new Simple("terror");
                    resNew = new Resultado(tAct);
                    resNew.setError(true);
                    int iNumFila = this.actual.getNumFila();
                    int iNumCol = this.actual.getNumColumna();
                    String errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_NO_TIPO_BASE_PUNT);
                    this.gestErr.escribeError(errorContextual);
                }
            } else {
                int tam = p.getTipoBase().getTam();
                instrMP = "new".concat("(").concat(String.valueOf(tam)).concat(")");
                this.bufferInstr.emite(instrMP);
            }
            instrMP = "desapila_ind";
            this.bufferInstr.emite(instrMP);
        }
        resNew.setError(err);
        return resNew;
    }

    private Resultado instDel() {
        Resultado resDel;
        ExprTipos tAct;
        CampoTS datoTS;
        String instrMP;
        this.reconoce("palRes", "dispose");
        resDel = this.mem();
        boolean err = !resDel.getTipoComp().getTipo().equals("puntero");
        if (!err) {
            Puntero p = (Puntero)resDel.getTipoComp();
            if (p.getTipoBase().getTipo().equals("ref")) {//Qué te apuestas a que esto no es así...
                //Este bloque va a haber que repasarlo...
                IdTipo id = (IdTipo) p.getTipoBase();
                if (this.existeID(id.getId())) {
                    datoTS = (CampoTS) this.tablaSimbolos.get(id.getId());
                    int tam = datoTS.getTipoComp().getTam();
                    instrMP = "del".concat("(").concat(String.valueOf(tam)).concat(")");
                    this.bufferInstr.emite(instrMP);
                } else {
                    tAct = new Simple("terror");
                    resDel = new Resultado(tAct);
                    resDel.setError(true);
                    int iNumFila = this.actual.getNumFila();
                    int iNumCol = this.actual.getNumColumna();
                    String errorContextual = this.construirMensajeError(iNumFila, iNumCol,
                                    ERR_NO_TIPO_BASE_PUNT);
                    this.gestErr.escribeError(errorContextual);
                }
            } else {
                int tam = p.getTipoBase().getTam();
                instrMP = "del".concat("(").concat(String.valueOf(tam)).concat(")");
                this.bufferInstr.emite(instrMP);
            }

        }
        resDel.setError(err);
        return resDel;
    }

    //{Expresion::= Termino0 RestoExpresion}
    private Resultado expresion(){
        Resultado resExpr;
        Resultado resTerm0;
        Resultado resRestoExpr;
        ExprTipos tipoExpr;
        String identificador;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Expresion::= Termino0 RestoExpresion}" );
        //resExpr = new Resultado();
        resTerm0 = this.term0();
        if (!this.abortar){
            tipoExpr = resTerm0.getTipoComp();
            identificador = resTerm0.getIdentificador();
            resRestoExpr = this.restoExpresion(tipoExpr,identificador);
            resExpr = new Resultado(resRestoExpr.getTipoComp());
            //resExpr.setTipo(resRestoExpr.getTipoComp());
            resExpr.setIdentificador(resRestoExpr.getIdentificador());
        } else {
            tipoExpr = new Simple("terror");
            resExpr = new Resultado(tipoExpr);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resExpr;
    }

    //{ Termino0 ::= Termino1 RestoTermino0}
    private Resultado term0(){
        Resultado resTerm0;
        Resultado resTerm1;
        Resultado resResTerm0;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino0 ::= Termino1 RestoTermino0}" );
        //resTerm0 = new Resultado();
        resTerm1 = this.term1();
        if(!this.abortar){
             resResTerm0 = this.restoTerm0(resTerm1.getTipoComp());//Hay que tratar los tipos
             resTerm0 =resResTerm0;
            //resTerm0.setTipo(resResTerm0.getTipo());
            //resTerm0.setIdentificador(resResTerm0.getIdentificador());
        } else {
            ExprTipos tipoAct;
            tipoAct = new Simple("terror");
            resTerm0 = new Resultado(tipoAct);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resTerm0;
    }
    
    //{Termino1 ::= Termino2 RestoTermino1}
    private Resultado term1(){
        Resultado resTerm1;
        Resultado resTerm2;
        Resultado resResTerm1;
        ExprTipos tipoTerm2;
        String identificador;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino1 ::= Termino2 RestoTermino1}" );
        resTerm1 = new Resultado();
        resTerm2 = this.term2();
        if (!this.abortar){
            tipoTerm2 = resTerm2.getTipoComp();
            identificador = resTerm2.getIdentificador();
            resResTerm1 = this.restoTerm1(tipoTerm2);//Hay que tratar los tipos
            resTerm1.setTipo(resResTerm1.getTipoComp());
            resTerm1.setIdentificador(resResTerm1.getIdentificador());
        }else
            resTerm1.setTipo(new Simple("terror"));
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resTerm1;
    }

    //{Termino2 ::= Termino3 RestoTermino2}
    private Resultado term2(){
        Resultado resTerm2;
        Resultado resTerm3;
        Resultado resResTerm2;
        ExprTipos tipoTerm3;
        String identificador;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino2 ::= Termino3 RestoTermino2}");
        resTerm2 = new Resultado();
        resTerm3 = this.term3();
        if (!this.abortar){
            tipoTerm3 = resTerm3.getTipoComp();
            identificador = resTerm3.getIdentificador();
            resResTerm2 = this.restoTerm2(tipoTerm3,identificador);
            resTerm2.setTipo(resResTerm2.getTipoComp());
            resTerm2.setIdentificador(resResTerm2.getIdentificador());
        } else
            resTerm2.setTipo(new Simple("terror"));
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resTerm2;
    }

   /* private Resultado term3(){
        Resultado resTerm3;
        Resultado resFact;
        String tipoTerm3;
        String operador;
        boolean cond;
        operador = this.tipoOp();
        if (operador.equals("opLog")){
            resTerm3 = this.term3();
            cond = (resTerm3.getTipo().equals("terror")) || !tiposOpLog(resTerm3.getTipo());
            if (cond){
                resTerm3.setTipo("terror");
            } else {
                //tipoTerm3 = tipoResultadoOpLog(resTerm3.getTipo());
                resTerm3.setTipo("nat");//Está mal. Sólo es para hacer una prueba
            }
        } else if (operador.equals("opConv")){
            resTerm3 = new Resultado();
            resFact = this.fact();
            cond = (resFact.getTipo().equals("terror")) || !tiposOpConv(resFact.getTipo());
            if (cond){
                resTerm3.setTipo("terror");
            } else {
                //tipoTerm3 = tipoResultadoOpConv(resFact.getTipo());
                tipoTerm3 = "real";//A pelo.Es para hacer una prueba
                resTerm3.setTipo(tipoTerm3);//Sólo para que compile. Está por hacer.
            }
        }else{
            resTerm3 = new Resultado();
            resFact = this.fact();
            resTerm3.setTipo(resFact.getTipo());
        }


        return resTerm3;
    }*/

    //{Termino3 ::= opLog Termino3 | ( RestoTermino3 | Fact}    
    private Resultado term3(){
        Resultado resTerm3;
        Resultado resResTerm3;
        Resultado resFact;
        String operador;
        String instrMP,tipoTerm3;
        String tipoAux="";
        String tipoOpLogFinal;
        boolean cond;
        String errorContextual;
        int numLin,numCol;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        operador = this.tipoOp();
        resTerm3 = new Resultado();
        if (operador.equals("opLog")) {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino3 ::= opLog Termino3}" );
            String tipoOpLog = this.actual.getTipoToken();
            String lexema = this.actual.getLexema();
            //Guardo aqui la posición de inicio del operador por si hay que dar un error de incompatibilidad de tipos.
            numLin = this.actual.getNumFila();
            numCol = this.actual.getNumColumna();
            this.reconoce(this.actual.getTipoToken());//Sólo para que avance
            resTerm3 = this.term3();
            if (!this.abortar){
                if (resTerm3.getTipo().equals("identificador")){
                    tipoAux = this.tipoID(resTerm3.getIdentificador());
                    tipoAux = this.tipoTraductor(tipoAux);
                }else
                    tipoAux = resTerm3.getTipo();
                if (tipoOpLog.equals("palRes")){
                    tipoOpLogFinal = lexema;
                } else{
                    tipoOpLogFinal = tipoOpLog;
                }
                tipoTerm3 = tipoUnario(tipoOpLogFinal, tipoAux);
                resTerm3.setTipo(new Simple(tipoTerm3));
//                resTerm3.setTipo(tipoTerm3);
                //Control del error incontextual de tipo imcompatible para ese operador.
                if (tipoTerm3.compareTo ("terror") == 0){
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                            // se inhibe la generación de código.
                    errorContextual = this.construirMensajeError(numLin, numCol,
                                        ERR_INCOMP_OPERADOR_OPERANDO, tipoOpLogFinal);                    
                    this.gestErr.escribeError(errorContextual);
                }                
                instrMP = this.generaCodigoOperadorLog(tipoOpLogFinal);
//                if (this.emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
//                }
            }else
                resTerm3.setTipo(new Simple("terror"));
        } else if (this.actual.getTipoToken().equals("(")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino3 ::= ( RestoTermino3}" );
            this.reconoce("(");//Sólo para que avance
            resResTerm3 = this.restoTerm3();
            resTerm3.setTipo(resResTerm3.getTipoComp());
        } else{
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Termino3 ::= Fact}" );
            resFact = this.fact();
            resTerm3.setTipo(resFact.getTipoComp());
            resTerm3.setIdentificador(resFact.getIdentificador());
        }

        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resTerm3;
    }

    //{RestoTermino3 ::= OpConv) Fact | Expresion)}
    private Resultado restoTerm3(){
        boolean palConv;
        String operador;
        String tipoOperador="";
        String tipoOperacion;
        Resultado resFact;
        Resultado resE;
        Resultado resRestoTerm3;
        String errorContextual;
        int numLin,numCol;
        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        operador = this.tipoOp();
        resRestoTerm3 = new Resultado();
        if (operador.equals("opConv")){
            //Guardo aqui la posición de inicio del operador por si hay que dar un error de incompatibilidad de tipos.
            numLin = this.actual.getNumFila();
            numCol = this.actual.getNumColumna();
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoTermino3 ::= OpConv) Fact}" );
            String tipoOperando = this.actual.getLexema();
            this.reconoce("palRes");//opConv es subconjunto del tipo palRes
            //String lexema = this.actual.getLexema();
            //lexema = lexema.concat(".0");
            this.reconoce(")");
            
            if (!this.abortar){
                resFact = this.fact();
                if (resFact.getTipo().equals("identificador")){
                    tipoOperador = this.tipoID(resFact.getIdentificador());
                    tipoOperador = this.tipoTraductor(tipoOperador);
                } else
                    tipoOperador = resFact.getTipo();
                tipoOperacion = this.tiposOperadorConversion(tipoOperando,tipoOperador);
                //Control del error incontextual de tipos imcompatibles para ese operador.
                if (tipoOperacion.equals ("terror") ){
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                            // se inhibe la generación de código.
                    errorContextual = this.construirMensajeError(numLin, numCol,
                                        ERR_INCOMP_OPERADOR_OPERANDO, tipoOperando);                    
                    this.gestErr.escribeError(errorContextual);
                }                
                String instrMP = this.generaCodigoOperadorConv(tipoOperando);
//                if (this.emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
//                }
                resRestoTerm3.setTipo(new Simple (tipoOperacion));
//                resRestoTerm3.setTipo(tipoOperacion);
            }else
                resRestoTerm3.setError(true);
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoTermino3 ::= Expresion)}" );
            resE = this.expresion();
            if (!this.abortar) {
                this.reconoce(")");
                resRestoTerm3.setTipo(resE.getTipoComp());
            }else
                resRestoTerm3.setError(true);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoTerm3;
    }

    //{Fact ::= iden | (Expresion) |  |Expresion|}
    private Resultado fact(){
        Resultado resE;
        Resultado resFact;
        CampoTS datoTs;
        String instrMP;
        String lexema;
        String cadDir,tipoAux,tipoAbs;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        resFact =new Resultado();

        if (this.tipoSimple(this.actual.getTipoToken())){
            if (!this.actual.getTipoToken().equals("identificador")){
                escribeFichTrazasSiModoTraza (this.iNivelProf, "{Fact ::= nat |integer |real |boolean |car |true |false}" );
                lexema = this.actual.getLexema();
                //El tipo de p.ej. true es palRes, luego necesita tratamiento aparte
                if (lexema.equals("true")||lexema.equals("false")){
                    tipoAux = "boolean";
                    //TRADUZCO LAS CONSTANTES BOOLEANAS a números equivalentes.
//                    if (lexema.equals("true"))
//                        lexema = "1";
//                    else
//                        lexema = "0";
                } else {
                    tipoAux = this.actual.getTipoToken();
                }
               // lexema =this.convierteLexema(tipoOp);
                instrMP = ("apila").concat("(").concat(lexema).concat(")");
                if (emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
                }
                resFact.setTipo(new Simple (tipoAux));
                this.reconoce(this.actual.getTipoToken());//Esta instrucción sí que me interesa dejarla así
            } else {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "{Fact ::= Mem}" );
                lexema = this.actual.getLexema();
                if (this.existeIDenTSNivAct(lexema)){
                    datoTs = (CampoTS)this.tablaSimbolos.get(lexema);
                } else {
                    this.errorVarNoDeclarada(lexema, this.actual.getNumFila(), this.actual.getNumColumna());
                    resFact.setTipo(new Simple("terror"));
                    resFact.setIdentificador(this.actual.getLexema());
                    //datoTs = new CampoTS("","",-1);
                    datoTs = null;//OJO!!! SÓLO PARA QUE COMPILE!!!
                }
               /* cadDir = String.valueOf(datoTs.getDir());
                instrMP = ("apila_dir").concat("(").concat(cadDir).concat(")");
                if (this.emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
                }
                //Una cosa es el tipo de un id en la tabla de símbolos, y otra cosa es aquí
                //Aquí el tipo es "identificador"
//                resFact.setTipo(this.actual.getTipo());
                resFact.setTipo(datoTs.getTipoComp());  //DUDA: creo que tiene que ser así
                resFact.setIdentificador(this.actual.getLexema());
                this.reconoce(this.actual.getTipoToken());//Sólo para que avance*/
                resFact = this.mem();
                String tipoTrad = this.tipoTraductor(resFact.getTipoComp().getTipo());
                if (this.tipoSimple(tipoTrad)){
                    instrMP = "apila_ind";
                    this.bufferInstr.emite(instrMP);
                } else {
                    int tam = resFact.getTipoComp().getTam();
                    instrMP = "mueve".concat("(").concat(String.valueOf(tam)).concat(")");
                    this.bufferInstr.emite(instrMP);
                }
            }
       
        } else if (this.actual.getTipoToken().equals("fin")) {
            resFact.setTipo(new Simple ("fin"));     //DUDA: ¿hay que crear una expresion de tipos nueva para este caso?
//            resFact.setTipo("fin");     //DUDA: ¿hay que crear una expresion de tipos nueva para este caso?
        } else if (this.actual.getTipoToken().equals("(")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Fact ::= (Expresion)}" );
            this.reconoce("(");//Para que avance
            resE = this.expresion();
            if (!this.abortar){
                this.reconoce(")");//Para que avance
//                resFact.setTipo(resE.getTipo());
                resFact.setTipo(resE.getTipoComp());
            }else
//                resFact.setTipo("terror");
                resFact.setTipo(new Simple("terror"));
        } else if (this.actual.getTipoToken().equals("|")){
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{Fact ::= |Expresion|}" );
            this.reconoce("|");//Para que avance
            resE = this.expresion();
            if (!this.abortar){
                this.reconoce("|");//Para que avance
                instrMP = "valor_absoluto";
//                if (resE.getTipo().equals("identificador")){
//                    tipoAux = this.tipoID(resE.getIdentificador());
//                } else tipoAux = resE.getTipo();
//                if (tipoAux.equals("real")){
//                    tipoAbs = tipoAux;
//                }else if (tipoAux.equals("integer")||tipoAux.equals("nat")){
//                    tipoAbs = "nat";
//                } else tipoAbs = "error";

//                if (this.emiteCodigo) {
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
//                }
//                resFact.setTipo(tipoAbs);
                resFact.setTipo(resE.getTipoComp());
            }else
//                resFact.setTipo("error");
                resFact.setTipo(new Simple("terror"));
        } else {
            this.abortar =true;
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resFact;
    }

    //{ RestoExpresion ::= OpComp Termino0 | Vacío}
    private Resultado restoExpresion (ExprTipos tipoExpr,String identificador){
        Resultado resRestoExpr;
        Resultado resTerm0;
        Resultado resE;
        boolean cond;
        boolean condErrorTipos;
        String instrMP;
        String operador;
        String tipoOp1="";
        String tipoOp2="";
        String errorContextual;
        int numLin,numCol;
        ExprTipos tipoResExpr;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        cond = this.opComp();
        //resRestoExpr = new Resultado();
        if (cond) {
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoExpresion ::= OpComp Termino0 }");
            operador = this.actual.getTipoToken();
            //Guardo aqui la posición de inicio del operador por si hay que dar un error de incompatibilidad de tipos.
            numLin = this.actual.getNumFila();
            numCol = this.actual.getNumColumna();
            this.reconoce(this.actual.getTipoToken());//Sólo para que avance
            resTerm0 = this.term0();
            if (!this.abortar) {
                /* A tener en cuenta : si sólo interesa conocer el String que identifica a un tipo,
                 * bien sea Simple o compuesto, basta con usar el método getTipo() de resultado,pues
                 * devuelve this.tipo.getTipo(). Si lo que queremos es acceder al objeto tipo completo,
                 * entonces sí que se debe usar el método getTipoComp(),
                 */
                //El operador1 es el que se recibe como parámetro.
                if (tipoExpr.getTipo().equals("identificador")) {
                    tipoOp1 = this.tipoID(identificador);
                } else {
                    tipoOp1 = tipoExpr.getTipo();
                }
                tipoOp1 = this.tipoTraductor(tipoOp1);
                //Operador2
                if (resTerm0.getTipo().equals("identificador")) {
                    tipoOp2 = this.tipoID(resTerm0.getIdentificador());
                } else {
                    tipoOp2 = resTerm0.getTipo();
                }
                tipoOp2 = this.tipoTraductor(tipoOp2);
                //Comprobación de compatibilidad de tipos
                if (!tiposComparacion(tipoOp1, tipoOp2)) {
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                    // se inhibe la generación de código.
                    errorContextual = this.construirMensajeError(numLin, numCol,
                                        ERR_INCOMP_OPERANDOS, operador);
                    this.gestErr.escribeError(errorContextual);
                }
                condErrorTipos = (tipoExpr.getTipo().equals("terror") || resTerm0.getTipo().equals("terror")
                        || (!tiposComparacion(tipoOp1, tipoOp2)));
                if (!condErrorTipos) {
                    //Despues de apilar los operandos emito la instruccion con la operacion
                    instrMP = this.generaCodigoOperadorComp(operador);
//                    if (this.emiteCodigo)
                        this.bufferInstr.emite(instrMP);
                    //El resultado es un valor booleano
                    tipoResExpr = new Simple("boolean");
                } else {
                    tipoResExpr = new Simple("terror");
                }
                resRestoExpr = new Resultado(tipoResExpr);
            } else {
                tipoResExpr = new Simple("terror");
                resRestoExpr = new Resultado(tipoResExpr);
                resRestoExpr.setError(true);
            } 
        } else {
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoExpresion ::= Vacío }");
            resRestoExpr = new Resultado(tipoExpr);
            resRestoExpr.setIdentificador(identificador);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoExpr;
    }

    //{ RestoTermino0 ::= FTerm0 RTerm0 | Vacío, donde
    //  FTerm0::= OpArit Term1 | or Term1 . Fusionado todo en el mismo método}
    private Resultado restoTerm0(ExprTipos tipoAct){//Falta gestionar los tipos
        Resultado resRestoTerm0;
        String instrMP;
        String tipoAux, tipoTrad1,tipoTrad2;
        String op;
        ExprTipos tipoNuevo;
        int etqSaltoCondicion;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        //Compruebo si es un operador aritmético
        if (this.opArit()){
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino0 ::= OpArit Term1 RestoTermino0 }");
            //Almaceno el operador en cuestión
            op =this.actual.getTipoToken();
            this.reconoce(this.actual.getTipoToken());//Para que avance
            //{FTerm0.cod = FTerm0.codh || Term1.cod || OpArit.op}
            //{FTerm0.etq = Term1.etq+1}
            resRestoTerm0 = this.term1();
            if (!this.abortar) {
                //Despues de apilar los operandos emito instruccion con la operacion
                instrMP = this.generaCodigoOperadorArit(op);
                // El eterno dilema de nuestro A.L. : lexema o tipo, ojo aquí
                this.bufferInstr.emite(instrMP);
                //{Term1.etqh = FTerm0.etqh+ 1}
                tipoTrad1 = this.tipoTraductor(tipoAct.getTipo());
                tipoTrad2 = this.tipoTraductor(resRestoTerm0.getTipoComp().getTipo());
                tipoAux = this.tiposArit(tipoTrad1, tipoTrad2, op);
                if (tipoAux.equals("nat")){
                    tipoNuevo = new Simple("nat");
                } else if (tipoAux.equals("integer")){
                    tipoNuevo = new Simple("integer");
                } else if (tipoAux.equals("char")){
                    tipoNuevo = new Simple("char");
                } else if (tipoAux.equals("boolean")){
                    tipoNuevo = new Simple("boolean");
                } else if (tipoAux.equals("real")) {
                    tipoNuevo = new Simple("real");
                } else {
                    tipoNuevo = new Simple("terror");
                }
                resRestoTerm0 = this.restoTerm0(tipoNuevo);
            }else{
                tipoNuevo = new Simple("terror");
                resRestoTerm0 = new Resultado(tipoNuevo);
                resRestoTerm0.setError(true);
            }
        } else if(this.actual.getLexema().equals("or")){    //compruebo si es el operador or
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino0 ::= or Term1 RestoTermino0 }");
            op =this.actual.getLexema();
            this.reconoce("palRes", this.actual.getLexema());//Para que avance
            //TRADUCCION DEL OPERADOR LOGICO OR EN CIRCUITO CORTO
            //{FTerm0.cod = FTerm0.codh || copia || ir-v(Term1.etq) || desapila || Term1.cod}
            //{FTerm0.etq = Term1.etq+3}
            this.bufferInstr.emite("copia");
            //Guardo el numero de la proxima instruccion que se va a escribir (la del salto)
            etqSaltoCondicion = bufferInstr.getEtq();
            this.bufferInstr.emite("ir-v(?)");
            this.bufferInstr.emite("desapila");
            resRestoTerm0=this.term1();
            if (!this.abortar) {
                //Completamos la instruccion de salto con la direccion correspondiente
                if (!this.bufferInstr.parchea(etqSaltoCondicion,this.bufferInstr.getEtq())){
                    resRestoTerm0.setError(true);
                }
                //AL EVALUAR EL OR EN CIRCUITO CORTO YA NO SE EMITE UNA INSTRUCCION OR PROPIAMENTE DICHA
//                //Despues de apilar los operandos emito instruccion con la operacion
//                instrMP = this.generaCodigoOperadorArityOr(op);
//                this.bufferInstr.emite(instrMP);
                //{Term1.etqh = FTerm0.etqh}
                tipoTrad1 = this.tipoTraductor(tipoAct.getTipo());
                tipoTrad2 = this.tipoTraductor(resRestoTerm0.getTipoComp().getTipo());
                tipoAux = this.tiposArit(tipoTrad1, tipoTrad2, op);
                if (tipoAux.equals("nat")){
                    tipoNuevo = new Simple("nat");
                } else if (tipoAux.equals("integer")){
                    tipoNuevo = new Simple("integer");
                } else if (tipoAux.equals("char")){
                    tipoNuevo = new Simple("char");
                } else if (tipoAux.equals("boolean")){
                    tipoNuevo = new Simple("boolean");
                } else {
                    tipoNuevo = new Simple("terror");
                }
                resRestoTerm0 = this.restoTerm0(tipoNuevo);
            }else{
                tipoNuevo = new Simple("terror");
                resRestoTerm0 = new Resultado(tipoNuevo);
                resRestoTerm0.setError(true);
            }
        } else {
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino0 ::= Vacio }");
            resRestoTerm0 = new Resultado(tipoAct);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoTerm0;
    }

    //{RestoTermino1 ::= FTerm1 RTerm1 | Vacio} donde
    //  FTerm1::= OpMult Term2 | and Term2 . Fusionado todo en el mismo método}
    private Resultado restoTerm1(ExprTipos e){
        Resultado resRestoTerm1;
        String instrMP,op;
        int etqSaltoCondicion, etqInstApila;
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        if (this.opMult()){
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino1 ::= OpMult Term2 RestoTermino1 }");
            op =this.actual.getTipoToken();
            this.reconoce(this.actual.getTipoToken());//Para que avance
            //{Term2.etqh = FTerm1.etqh+ 1}
            resRestoTerm1 = this.term2();
            if (!this.abortar) {
                //PENDIENTE: EVLAUAR LA COMPATIBILIDAD DE LOS OPERANDOS
                // Y DETERMINAR EL TIPO DEL RESULTADO.
                //Despues de apilar los operandos emito instruccion con la operacion
                instrMP = this.generaCodigoOpMult(op);
                this.bufferInstr.emite(instrMP);
                //{FTerm1.cod = FTerm1.codh || Term1.cod || OpMult.op}
                //{FTerm1.etq = Term2.etq+1}
                resRestoTerm1 = this.restoTerm1(e);//Esto no es sólo así
            }else{
                resRestoTerm1 = new Resultado(new Simple("terror"));
                resRestoTerm1.setError(true);
            }
        } else if(this.actual.getLexema().equals("and")){
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino1 ::= and Term2 RestoTermino1 }");
            this.reconoce("palRes", this.actual.getLexema());//Para que avance
            //{Term2.etqh = FTerm1.etqh}
            //TRADUCCION DEL OPERADOR LOGICO AND EN CIRCUITO CORTO
            //{FTerm1.cod = FTerm1.codh || ir-f(Term2.etq+1) || Term2.cod || ir-a(Term2.etq+2) || apila(0)}
            //{FTerm1.etq = Term2.etq+2}??
            //Guardo el numero de la proxima instruccion que se va a escribir (la del salto)
            etqSaltoCondicion = bufferInstr.getEtq();
            this.bufferInstr.emite("ir-f(?)");
            resRestoTerm1=this.term2();
            if (!this.abortar) {
                //PENDIENTE: EVLAUAR LA COMPATIBILIDAD DE LOS OPERANDOS.
                // Y DETERMINAR EL TIPO DEL RESULTADO.
                //Etq contiene el numero de la siguiente instruccion a emitir ("ir-a"). Si le sumo 2 al contador
                //salto a la instruccion que sigue al apila(0).
                this.bufferInstr.emite("ir-a(" + (this.bufferInstr.getEtq() + 2) + ")");
                etqInstApila = this.bufferInstr.getEtq();
                this.bufferInstr.emite("apila(false)"); //apilo false (pongo en la pila el valor falso)
                //Completamos la instruccion de salto con la direccion correspondiente
                if (!this.bufferInstr.parchea(etqSaltoCondicion,etqInstApila)){
                    resRestoTerm1.setError(true);
                }
                resRestoTerm1 = this.restoTerm1(e);//Esto no es sólo así
            }else{
                resRestoTerm1 = new Resultado(new Simple("terror"));
                resRestoTerm1.setError(true);
            }
        } else {
            escribeFichTrazasSiModoTraza(this.iNivelProf, "{ RestoTermino1 ::= Vacio }");
            resRestoTerm1 = new Resultado(e);//Esto no es así,recordar que falta el tema de los tipos
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoTerm1;
    }

    //{RestoTermino2 ::= opDespl Termino2 | Vacio}
    private Resultado restoTerm2 (ExprTipos tipoTerm3,String identificador){
        Resultado resRestoTerm2;
        Resultado resTerm2;
        boolean cond;
        boolean condTipos;
        String instrMP,operador,tiposDespl,tipoTrad1,tipoTrad2;
        String tipoOp1="";
        String tipoOp2="";
        String errorContextual;
        int numLin,numCol;
        ExprTipos tipoAct;

        
        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        cond =this.opDespl();
        resRestoTerm2 = new Resultado();
        if (cond) {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoTermino2 ::= opDespl Termino2}" );
            operador = this.actual.getTipoToken();
            //Guardo aqui la posición de inicio del operador por si hay que dar un error de incompatibilidad de tipos.
            numLin = this.actual.getNumFila();//Automáticamente casting a String
            numCol = this.actual.getNumColumna();
            this.reconoce(operador);//Sólo para que avance
            resTerm2 = this.term2();
            /*condTipos = tipoTerm3.equals("terror") || resTerm2.getTipo().equals("terror")
                    || !tiposDespl(tipoTerm3,resTerm2.getTipo());
            if (condTipos) {
                resRestoTerm2.setTipo("terror");
            } else {
                tiposResultadoDesp(resTerm2.getTipo(),tipoTerm3);
                instrMP = generaCodigoOperadorDesp(operador);
                this.bufferInstruc.emite(instrMP);
            }*/
            if (!this.abortar){
                if (tipoTerm3.getTipo().equals("identificador")){
                    tipoOp1=this.tipoID(identificador);
                } else {
                    tipoOp1 = tipoTerm3.getTipo();
                }
                if (resTerm2.getTipoComp().getTipo().equals("identificador")){
                    tipoOp2 = this.tipoID(resTerm2.getIdentificador());
                } else {
                    tipoOp2 = resTerm2.getTipoComp().getTipo();
                }
                tipoTrad1 = this.tipoTraductor(tipoOp1);
                tipoTrad2 = this.tipoTraductor(tipoOp2);
                tiposDespl = this.tiposDesplazamiento(tipoTrad1, tipoTrad2);
                //Control del error incontextual de tipos imcompatibles para ese operador.
                if (tiposDespl.compareTo ("terror") == 0){
                    this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                            // se inhibe la generación de código.
                        errorContextual = this.construirMensajeError(numLin, numCol,
                                            ERR_INCOMP_OPERANDOS, operador);
                    this.gestErr.escribeError(errorContextual);
                    tipoAct = new Simple("terror");
                }
                instrMP = generaCodigoOperadorDesp(operador);
//                if (this.emiteCodigo){
                    this.bufferInstr.emite(instrMP);
//                    this.etq++;
//                }
                tipoAct = new Simple("nat");
                resRestoTerm2.setTipo(tipoAct);
            } else
                resRestoTerm2.setTipo(new Simple ("terror"));
        } else {
            escribeFichTrazasSiModoTraza (this.iNivelProf, "{RestoTermino2 ::= Vacio}" );
            resRestoTerm2.setTipo(tipoTerm3);
            resRestoTerm2.setIdentificador(identificador);
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
        return resRestoTerm2;
    }

    private boolean tipoSimple (String tipo){
        boolean cond;
        //Se incluye también el tipo boolean
        cond = (tipo.equals("nat") || tipo.equals("real")|| tipo.equals("integer") ||
                tipo.equals("palRes") || tipo.equals("car") || tipo.equals("boolean") ||
                tipo.equals("identificador"));
        return cond;
    }

    private boolean lexemaTipoSimple (String Lexema){
        return (Lexema.equals("integer") || Lexema.equals("float")||
            Lexema.equals("character") || Lexema.equals("natural") ||
            Lexema.equals("boolean"));
    }
 
/**
 * Determina si el token recibido como parámetro coincide con el token actual,
 * según las reglas definidas en la gramática. Si se produce coincidencia se avanza 
 * la lectura al siguiente token, pero si no coinciden se produce un error sintáctico
 * que se indica activando una variable global de error.
 * @param tipoToken
 */
    private void reconoce (String tipoToken){

        String errorSintaxis,tokenEsperado,tokenRecibido;
        String numLin,numCol;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        if (!this.abortar) {
            if (this.actual.getTipoToken().equals(tipoToken)) {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "---> Tok: " + tipoToken + " ,Lex: " + this.actual.getLexema());
                this.actual = this.lex.siguienteToken();
            } else {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "ERROR ---> Tok: " + tipoToken + " ,Lex: " + this.actual.getLexema());
                this.abortar = true;
                tokenEsperado = tipoToken;
                tokenRecibido = this.actual.getTipoToken();
                numLin = this.actual.getNumFila()+" ";//Automáticamente casting a String
                numCol = this.actual.getNumColumna()+" ";
                if (tokenEsperado.equals("fin")){
                    errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                        ERR_TOKEN_NO_ESPERADO_2, tokenEsperado, tokenRecibido + " y lexema: " + this.actual.getLexema());
//                    errorSintaxis = "ERROR SINTÁCTICO INCONTEXTUAL en línea " + numLin + " y columna " +
//                            numCol + ": ";
//                    errorSintaxis += "Se esperaba: " + tokenEsperado + " ,o bien se esperaba ;" +
//                            " , pero se recibe: " + tokenRecibido;
                } else {
                    errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                        ERR_TOKEN_NO_ESPERADO, tokenEsperado, tokenRecibido + " y lexema: " + this.actual.getLexema());
//                    errorSintaxis = "ERROR SINTÁCTICO INCONTEXTUAL en línea " + numLin + " y columna " +
//                            numCol + ": ";
//                    errorSintaxis += "Se esperaba: " + tokenEsperado + " , pero se recibe: " + tokenRecibido;
                }
                this.gestErr.escribeError(errorSintaxis);
            }
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
    }

/**
 * Determina si el token recibido como parámetro coincide con el token actual, y además
 * su lexema coincide con el especificado. Si se produce coincidencia se avanza
 * la lectura al siguiente token, pero si no coinciden se produce un error sintáctico
 * que se indica activando una variable global de error.
 * @param tipoToken: token a reconocer
 * @param sLexema: lexema a reconocer
 */
    private void reconoce (String tipoToken, String sLexema){

        String errorSintaxis,tokenEsperado,tokenRecibido;
        String numLin,numCol;

        //Bajo en el árbol sintáctico.
        this.iNivelProf++;
        if (!this.abortar) {
            if (this.actual.getTipoToken().equals(tipoToken) && this.actual.getLexema().equals(sLexema)) {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "---> Tok: " + tipoToken + " ,Lex: " + this.actual.getLexema());
                this.actual = this.lex.siguienteToken();
            } else {
                escribeFichTrazasSiModoTraza (this.iNivelProf, "ERROR ---> Tok: " + tipoToken + " ,Lex: " + this.actual.getLexema());
                this.abortar = true;
                tokenEsperado = tipoToken;
                tokenRecibido = this.actual.getTipoToken();
//                numLin = this.actual.getNumFila()+" ";//Automáticamente casting a String
//                numCol = this.actual.getNumColumna()+" ";
                if (tokenEsperado.equals("fin")){
                    errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                        ERR_TOKEN_NO_ESPERADO_2, 
                                        tokenEsperado + " y lexema: " +sLexema, 
                                        tokenRecibido + " y lexema: " + this.actual.getLexema());
                    
//                    errorSintaxis = "ERROR SINTÁCTICO INCONTEXTUAL en línea " + numLin +
//                    "y columna " + numCol + ": Se esperaba: " + tokenEsperado + " y lexema: " + sLexema +
//                    " ,o bien se esperaba ;" + " , pero se recibe: " + tokenRecibido + " y lexema: " + this.actual.getLexema();
                } else {
                    errorSintaxis = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                                        ERR_TOKEN_NO_ESPERADO, 
                                        tokenEsperado + " y lexema: " +sLexema, 
                                        tokenRecibido + " y lexema: " + this.actual.getLexema());
//                    errorSintaxis =
//                        "ERROR SINTÁCTICO INCONTEXTUAL en línea " + numLin +
//                        "y columna " + numCol + ": Se esperaba: " + tokenEsperado + " y lexema: " + sLexema +
//                        " , pero se recibe: " + tokenRecibido + " y lexema: " + this.actual.getLexema();
                }
                this.gestErr.escribeError(errorSintaxis);
            }
        }
        //Subo en el árbol sintáctico.
        this.iNivelProf--;
    }

    private boolean existeID (String identificador){
        boolean res;
        res = this.tablaSimbolos.containsKey(identificador);
        return res;
    }

    private boolean existeIDenTSNivAct (String identificador){
        boolean res;
        res = this.tablaSimbolos.containsKeyTSActual(identificador);
        return res;
    }

    private boolean esPalRes (String identificador){
        return this.lex.getListaPalRes().containsKey(identificador);
    }

    private boolean tiposOpLog (String tipo){
        return tipo.equals("boolean");
    }

    private boolean tiposOpConv (String tipo){
        return !tipo.equals("boolean");
    }

    private boolean opComp(){
        boolean res;
        String tipoComp = this.actual.getTipoToken();
        res = tipoComp.equals("<") || tipoComp.equals("<=") || tipoComp.equals(">") 
                || tipoComp.equals(">=") || tipoComp.equals("=")|| tipoComp.equals("=/=");
        return res;
    }

    private boolean opArit(){
        boolean res;
        res = (this.actual.getTipoToken().equals("+") || this.actual.getTipoToken().equals("-"));
        //Ahora el or es una categoría sintáctica diferente.
//                || this.actual.getLexema().equals("or")/*Para este último es lexema*/);
        return res;
    }

    private boolean opMult(){
        boolean res;
        res = (this.actual.getTipoToken().equals("*") || this.actual.getTipoToken().equals("/")
                || this.actual.getTipoToken().equals("%"));
        //Ahora el and es una categoría sintáctica diferente.
//                || this.actual.getTipoToken().equals("%")) || this.actual.getLexema().equals("and");
        return res;
    }

    private boolean opDespl(){
        return this.actual.getTipoToken().equals(">>") || this.actual.getTipoToken().equals("<<");
    }

    private String tiposArit(String tipo1,String tipo2, String operador){
        String res="";
        if (operador.equals("+")||operador.equals("-")){
            if (tipo1.equals("real") || tipo2.equals("real")){
                res = "real";
            } else if (tipo1.equals("integer")||tipo2.equals("integer")){
                res = "integer";
            } else if (tipo1.equals("nat") && tipo2.equals("nat")){
                res = "nat";
            } else res = "error";
        } else if (operador.equals("or")){
            if (tipo1.equals("boolean") && tipo2.equals("boolean")){
                res = "boolean";
            } else res = "error";
        }else res = "error";
        return res;
    }

    private String tiposMult(String tipo1,String tipo2,String operador){
        String res;
        if (operador.equals("*")||operador.equals("/")){
            if (tipo1.equals("real")||tipo2.equals("real")){
                res = "real";
            } else if (tipo1.equals("integer")||tipo2.equals("integer")){
                res = "integer";
            } else if (tipo1.equals("nat")&&tipo2.equals("nat")){
                res = "nat";
            } else res = "error";
        } else if (operador.equals("%")) {
            if ((tipo1.equals("nat")||tipo1.equals("integer")) && tipo2.equals("nat")){
                res = tipo1;
            } else
                res = "error";
        } else if (operador.equals("and")){
            if ((tipo1.equals("boolean") && tipo2.equals("boolean"))){
                res = "boolean";
            } else res = "error";
        } else res = "error";
        return res;
    }

    private String tiposDespl(String tipo1,String tipo2){
        String res ="";
        if (tipo1.equals("nat")&&tipo2.equals("nat")){
            res = "nat";
        } else res ="error";
        return res;
    }

    private boolean tiposComparacion(String tipo1, String tipo2){
        boolean num;
        boolean car;
        boolean bool;
        num = this.esNum(tipo1) && this.esNum(tipo2);
        car = this.esCar(tipo1) && this.esCar(tipo2);
        bool = this.esBool(tipo1) && this.esBool(tipo2);
        return num || car || bool;
    }

    private String tipoUnario (String operador,String tipo){
        String res ="";
        //Adaptado para devolver los literales de tipo que se manejan ahora.
        if (operador.compareTo("not") == 0){
            if (tipo.equals("boolean"))
                res="boolean";
            else res = "terror";
        } else {    //Operadores -, +
            if ((tipo.equals("nat")||tipo.equals("integer"))){
                res = "integer";
            } else if (tipo.equals("real")){
                res = "real";
            } else res = "terror";
        }
        return res;
    }

    private String tiposOperadorConversion (String operador,String tipo){
        String res ="";
        if (!tipo.equals("boolean")){
            if (operador.equals("float")){
                res = "real";
            } else if (operador.equals("int")){
                res = "integer";
            } else if (operador.equals("nat")){
                if (tipo.equals("nat") || tipo.equals("car")){
                    res = "nat";
                } else res = "terror";
            } else if (operador.equals("char")){
                if (tipo.equals("nat") || tipo.equals("car")){
                     res = "car";
                 } else res = "terror";
            } else res ="terror";
        } else res = "terror";
        return res;
    }

    private String tiposDesplazamiento (String tipo1, String tipo2){
        String res ="";
        if (tipo1.equals("nat")&&tipo2.equals("nat")){
            res="nat";
        } else res="error";
        return res;
    }

   /* private String tipoResultadoArit(String tipo1, String tipo2){
        return "nat";//De momento
    }

    private String tipoResultadoMult(String tipo1, String tipo2){
        return "nat";//De momento
    }

    private String tiposResultadoDesp(String tipo1, String tipo2){
        return null;//Por hacer
    }*/

    private boolean tiposAsignacion (String tipoID,String tipoExpr){
        boolean res = false;
        if (tipoID.equals("nat")) {
            res = tipoExpr.equals("nat");
        } else if (tipoID.equals("boolean")){
            res = tipoExpr.equals("boolean");
        } else if (tipoID.equals("car")){
            res = tipoExpr.equals("car");
        } else if (tipoID.equals("integer")){
            res = (tipoExpr.equals("nat") || tipoExpr.equals("integer"));
        } else if (tipoID.equals("real")){
            res = ((tipoExpr.equals("nat") || tipoExpr.equals("integer")) || tipoExpr.equals("real"));
        }
        return res;
    }

    private String generaCodigoOperadorArit(String operador){
        String res = "";
        if (operador.equals("+")){
            res = "suma";
        } else if (operador.equals("-")){
            res = "resta";
        } else if (operador.equals("or")){ //por aqui ya no va a entrar, se evalúa en circuito corto
            res = "or";
        }
        return res;
    }

    private String generaCodigoOperadorLog(String operador){
        String res = "";
        if (operador.equals("-")){
            res = "cambia_signo";
        }else if (operador.equals("+")){
            res = "convierte_a_int";

        } else if (operador.equals("not")){
            res = "niega";
        }
        return res;
    }

    private String generaCodigoOperadorComp(String operador){
        String res ="";
        if (operador.equals("<")){
            res = "menor";
        }else if (operador.equals("<=")){
            res = "menorigual";
        }else if (operador.equals(">")){
            res = "mayor";
        }else if (operador.equals(">=")){
            res = "mayorigual";
        }else if(operador.equals("=")){
            res = "igual";
        }else if (operador.equals("=/=")){
            res= "distinto";
        }
        return res;
    }

    private String generaCodigoOperadorConv(String operador){
        String res ="";
        if (operador.equals("float")){
            res = "convierte_a_real";
        } else if (operador.equals("int")){
            res = "convierte_a_int";
        } else if (operador.equals("nat")){
            res = "convierte_a_nat";
        } else if (operador.equals("char")){
            res = "convierte_a_char";
        }
        return res;
    }

    private String generaCodigoOperadorDesp(String operador){
        String res="";
        if (operador.equals(">>")){
            res = "desplaza_derecha";
        } else if (operador.equals("<<")){
            res = "desplaza_izquierda";
        }
        return res;
    }

    private String generaCodigoOpMult (String operador){
        String res ="";
        if (operador.equals("*")){
            res="multiplica";
        } else if (operador.equals("%")){
            res = "mod";
        } else if (operador.equals("and")){
            res = "and";    //por aqui ya no va a entrar, se evalúa en circuito corto
        } else if (operador.equals("/")){
            res = "divide";
        }
        return res;
    }

    private String generaCodigoOpLectura (String tipo){
        String res="";
        if (tipo.equals("nat")){
            res = "apila_entradaNatural";
        } else if (tipo.equals("integer")){
            res = "apila_entradaEntero";
        } else if (tipo.equals("real")){
            res= "apila_entradaReal";
        } else if (tipo.equals("car")){
            res ="apila_entradaChar";
        } else if (tipo.equals("boolean")){
            res = "apila_entradaBooleano";
        }
        return res;
    }

    private String generaCodigoOpEscritura (String tipo){
        String res="";
        if (tipo.equals("identificador")){
            res = "out_dir";
        } else {
            res = "out";
        }
        return res;
    }

    private boolean esNum (String dato){
        boolean cond;
        cond = dato.equals("nat") || dato.equals("real") || dato.equals("integer");
        return cond;
    }

    private boolean esCar (String dato){
        return dato.equals("car");
    }

    private boolean esBool (String dato){
        return dato.equals("boolean");
    }

    private String castingTipos(String tipoID, String tipoExpr){
        boolean condIDReal;
        boolean condIDInt;
        boolean condIDNat;
        String res="";
        condIDReal = (!tipoExpr.equals("car")&&
                (tipoExpr.equals("integer")||tipoExpr.equals("nat")));
        condIDInt = (!tipoExpr.equals("car"))&&
                (tipoExpr.equals("nat"));
        condIDNat = (!tipoExpr.equals("car")&&tipoExpr.equals("car"));
        if ((tipoID.equals("real")) && condIDReal){
            res="convierte_a_real";
        }else if (tipoID.equals("integer")&&(condIDInt)) {
            res="convierte_a_int";
        }else if (tipoID.equals("nat")&&condIDNat){
            res="conviete_a_nat";
        }
        return res;
    }

    private String convierteLexema (String tipoConv){
        if (!tipoConv.equals("")) {
            return this.actual.getLexema().concat(".0");//Una prueba
        } else {
            return this.actual.getLexema();//Una prueba
        }

    }

    private void errorTiposArit(int iNumLinea, int iNumCol, String sOperador){
        String errorContextual,numLin,numCol;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
        errorContextual = this.construirMensajeError(iNumLinea, iNumCol,
                    ERR_INCOMP_OPERANDOS, sOperador);
        this.gestErr.escribeError(errorContextual);
    }

    private void errorTiposAsig(){
        String errorContextual,numLin,numCol;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
//        numLin = this.actual.getNumFila()+" ";//Automáticamente casting a String
//        numCol = this.actual.getNumColumna()+" ";
        errorContextual = this.construirMensajeError(this.actual.getNumFila(), this.actual.getNumColumna(), 
                    ERR_INCOMP_TIPOS_ASIG);
        
//        errorContextual = "ERROR SINTÁCTICO CONTEXTUAL en línea "  + numLin +
//            "y columna " + numCol + ". ";
//        errorContextual += "Tipos incompatibles para la asignación ";
        this.gestErr.escribeError(errorContextual);
    }

    private void errorVarNoDeclarada (String id, int numLin, int numCol){
        String errorContextual;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
        errorContextual = this.construirMensajeError(numLin, numCol,
                    ERR_VAR_NO_DECLARADA, id);
        this.gestErr.escribeError(errorContextual);
    }

    private void errorVariableDuplicada(String id, int numLin, int numCol){
        String errorContextual;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
        errorContextual = this.construirMensajeError(numLin, numCol, ERR_VAR_YA_DECLARADA, id);
        this.gestErr.escribeError(errorContextual);
    }

    private void errorTipoErroneo(String id, int numLin, int numCol){
        String errorContextual;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
        errorContextual = this.construirMensajeError(numLin, numCol, ERR_TIPO_ERRONEO, id);
        this.gestErr.escribeError(errorContextual);
    }

    private void errorPalabraReservada(String id, int numLin, int numCol){
        String errorContextual;
        this.emiteCodigo = false;//Si se produce un error contextual, no se para, pero
                                    // se inhibe la generación de código.
        errorContextual = this.construirMensajeError(numLin, numCol, ERR_VAR_ES_PALRES, id);
        this.gestErr.escribeError(errorContextual);
    }

    private String tipoID (String id){
        String res="";
        CampoTS datoTS;
        if (this.existeID(id)) {
            datoTS = (CampoTS) this.tablaSimbolos.get(id);
            res = datoTS.getTipo();
        }
        return res;
    }
    
    private void escribeFichTrazasSiModoTraza (int iNivel, String sCadena){
        if (this.bModoTraza){
            for (int i= 0; i< iNivel; i++)
                sCadena = "  " + sCadena;
            sCadena += "\r\n";
            this.archivoTrazas.escribe(sCadena);
            this.consolaDebug.getTextAreaReglas().setText(this.consolaDebug.getTextAreaReglas().getText() + sCadena);
        }
    }

//    private void parchea(int dirInstIgnorante, int dirInstConocida){
//        this.cod.parchea(dirInstIgnorante, dirInstConocida);
//        this.cod.recuperaArchivo();//Estamos de nuevo al final para seguir añadiendo código.
//    }


    private void generaCodigoIncrementoVariable(String dirID){
        String Instr = ("apila(").concat(dirID).concat(")");
        this.bufferInstr.emite(Instr);
        this.bufferInstr.emite("apila_ind");
        this.bufferInstr.emite("apila(1)");
        this.bufferInstr.emite("suma");
    }

    private boolean compatiblesComp (ExprTipos e1, ExprTipos e2){
        //Si visitadas e1 y e2, devolver cierto
        String tipoTradE1, tipoTradE2;
        ExprTipos tipo1,tipo2;
        CampoReg campo1,campo2;
        campo1 = null;
        campo2 = null;
        tipo1 = null;
        tipo2 = null;
        boolean tiposAsig;
        if (this.visitadas.containsKey(e1.getTipo()) && this.visitadas.containsKey(e2.getTipo())){//No sé si esto es así
            return true;
        } else {
            this.visitadas.put(e1.getTipo(), e1);
            this.visitadas.put(e2.getTipo(), e2);
        }
        tipoTradE1 = this.tipoTraductor(e1.getTipo());
        tipoTradE2 = this.tipoTraductor(e2.getTipo());
        tiposAsig = this.tiposAsignacion(tipoTradE1, tipoTradE2);
        if (tiposAsig && tipoSimple(tipoTradE1)) {//De momento lo dejo así
            return this.tiposAsignacion(tipoTradE1, tipoTradE2);
        } else if (e1.getTipo().equals(e2.getTipo()) && e1.getTipo().equals("array")) {
            Array aux1 = (Array) e1;
            Array aux2 = (Array) e2;
            boolean res = (aux1.getNumElems() == aux2.getNumElems());
            if (res) {
                return compatiblesComp(aux1.getTipoBase(),aux2.getTipoBase());//Para que compile, todavía no acabado
            } else return false;//Para que compile, todavía no acabado
        } else if (e1.getTipo().equals(e2.getTipo()) && e1.getTipo().equals("record")) {
            Registro reg1 = (Registro) e1;
            Registro reg2 = (Registro) e2;
            boolean numCampos = (reg1.getNumCampos() == reg2.getNumCampos());
            if (numCampos) {
                Enumeration keysReg1 = reg1.getCampos().elements();
                Enumeration keysReg2 = reg2.getCampos().elements();
                while (keysReg1.hasMoreElements()){
                    campo1 = (CampoReg)keysReg1.nextElement();
                    campo2 = (CampoReg)keysReg2.nextElement();
                    if (!compatiblesComp(campo1.getTipo(),campo2.getTipo())) {
                        return false;
                    }
                }
                   
                return true;
            } else {
                return false;
            }
        } else if (e1.getTipo().equals(e2.getTipo()) && e1.getTipo().equals("puntero")){
            Puntero punt1 = (Puntero)e1;
            Puntero punt2 = (Puntero)e2;
            return compatiblesComp(punt1.getTipoBase(),punt2.getTipoBase());
        } else if (e1.getTipo().equals("ref")) {
            ExprTipos tipoNom1 = this.refAlias(e1);
            return compatiblesComp(tipoNom1, e2);
        } else if (e2.getTipo().equals("ref")) {
            ExprTipos tipoNom2 = this.refAlias(e2);
            return compatiblesComp(e1, tipoNom2);
        } else {
            return false;
        }
    }

    private ExprTipos refAlias (ExprTipos e){
        ExprTipos resRefAlias;
        if (e.getTipo().equals("ref")){
            IdTipo nom = (IdTipo)e;
            if (this.existeID(nom.getId())){
                CampoTS datoTS = (CampoTS)this.tablaSimbolos.get(nom.getId());
                ExprTipos tipoAct = datoTS.getTipoComp();
                return refAlias (tipoAct);
            } else {
                ExprTipos tipoError = new Simple("terror");
                return tipoError;
            }
        } else return e;
    }

    private boolean referenciaErronea (ExprTipos e){
        boolean res;
        if (e.getTipo().equals("ref")){
            IdTipo nom = (IdTipo)e;
            res = !this.existeID(nom.getId());
        } else res =false;
        return res;
    }

    private ArrayList juntarPend (ArrayList l1, ArrayList l2){
        ArrayList resJuntarPend = new ArrayList();
        int pos;
        if (l1 != null && l2 != null) {
            for (int i = 0; i < l1.size(); i++) {
                resJuntarPend.add(l1.get(i));
            }

            for (int i = 0; i < l2.size(); i++) {
                pos = l1.indexOf(l2.get(i));
                if (pos == -1) {
                    resJuntarPend.add(l2.get(i));
                }
            }
        }
        return resJuntarPend;
    }

    private String construirMensajeError(int iNumFila, int iNumCol, int codError){
        return construirMensajeError(iNumFila, iNumCol, codError, "", "");
    }
    
    private String construirMensajeError(int iNumFila, int iNumCol, int codError, String sParam1){
        return construirMensajeError(iNumFila, iNumCol, codError, sParam1, "");
    }

    private String construirMensajeError(int iNumFila, int iNumCol, int codError, String sParam1, String sParam2){
        String sCadena = "ERROR SINTÁCTICO " + mensajesError[codError][0] + " en línea "  + iNumFila +
            " y columna " + iNumCol + ". " + mensajesError[codError][1];
        //Reemplazo las interrogaciones(parametros) por sus valores correspondientes
        int iPosicion = sCadena.indexOf("?");
        if (iPosicion != -1){
            //Reemplazo el parametro 1
            sCadena = sCadena.substring(0, iPosicion) + sParam1 + sCadena.substring(iPosicion +1);
            iPosicion = sCadena.indexOf("?");
            if (iPosicion != -1)
            //Reemplazo el parametro 2
            sCadena = sCadena.substring(0, iPosicion) + sParam2 + sCadena.substring(iPosicion +1);
        }
        return sCadena;
    }

    private ArrayList eliminarPendiente (ArrayList pend1, String id){
        ArrayList resultado;
        int pos = pend1.indexOf(id);
        if (pos!=-1){
            pend1.remove(pos);
        }
        return pend1;
    }
}
